Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://www.mooseframework.org
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "AbaqusUtils.h"
11 : #include "MooseUtils.h"
12 : #include "libmesh/threads.h"
13 :
14 : // MPI
15 :
16 : const libMesh::Parallel::Communicator * AbaqusUtils::_communicator = nullptr;
17 :
18 : void
19 76 : AbaqusUtils::setCommunicator(const libMesh::Parallel::Communicator * communicator)
20 : {
21 76 : if (_communicator != nullptr && communicator != _communicator)
22 : mooseWarning("Conflicting MPI communicators specified in Abaqus compatibility objects. Are you "
23 : "running a multiapps simulation?");
24 :
25 76 : _communicator = communicator;
26 76 : }
27 :
28 : extern "C" void
29 94 : getnumcpus_(int * num)
30 : {
31 : auto communicator = AbaqusUtils::getCommunicator();
32 94 : *num = communicator->size();
33 94 : }
34 :
35 : extern "C" void
36 94 : getrank_(int * rank)
37 : {
38 : auto communicator = AbaqusUtils::getCommunicator();
39 94 : *rank = communicator->rank();
40 94 : }
41 :
42 : extern "C" MPI_Comm
43 30 : get_communicator()
44 : {
45 : auto communicator = AbaqusUtils::getCommunicator();
46 30 : return communicator->get();
47 : }
48 :
49 : // Threads
50 :
51 : extern "C" int
52 4744 : getnumthreads_()
53 : {
54 4744 : return libMesh::n_threads();
55 : }
56 :
57 : extern "C" int
58 4675 : get_thread_id_()
59 : {
60 : ParallelUniqueId puid;
61 4675 : return puid.id;
62 : }
63 :
64 : // Output directory
65 :
66 : std::string AbaqusUtils::_output_dir = "";
67 : std::string AbaqusUtils::_job_name = "";
68 :
69 : void
70 76 : AbaqusUtils::setInputFile(const std::string & input_file)
71 : {
72 76 : auto split = MooseUtils::splitFileName(input_file);
73 76 : auto output_dir = split.first;
74 152 : auto job_name = MooseUtils::stripExtension(split.second);
75 :
76 124 : if (!_output_dir.empty() && output_dir != _output_dir)
77 : mooseWarning("Conflicting output directories specified in Abaqus compatibility objects: ",
78 : output_dir,
79 : " != ",
80 : _output_dir,
81 : ". Are you running a multiapps simulation?");
82 :
83 76 : if (!_job_name.empty() && job_name != _job_name)
84 : mooseWarning("Conflicting job names specified in Abaqus compatibility objects: ",
85 : job_name,
86 : " != ",
87 : _job_name,
88 : ". Are you running a multiapps simulation?");
89 :
90 152 : _output_dir = output_dir;
91 : _job_name = job_name;
92 76 : }
93 :
94 : extern "C" void
95 62 : getoutdir_(char * dir, int * len)
96 : {
97 : auto output_dir = AbaqusUtils::getOutputDir();
98 62 : *len = output_dir.length();
99 15934 : for (int i = 0; i < 256; ++i)
100 15872 : dir[i] = i < *len ? output_dir[i] : ' ';
101 62 : }
102 :
103 : extern "C" void
104 62 : getjobname_(char * dir, int * len)
105 : {
106 : auto job_name = AbaqusUtils::getJobName();
107 62 : *len = job_name.length();
108 15934 : for (int i = 0; i < 256; ++i)
109 15872 : dir[i] = i < *len ? job_name[i] : ' ';
110 62 : }
111 :
112 : // error/warning/info message output
113 :
114 : extern "C" void
115 85 : stdb_abqerr_(int * lop, char * format, int * intv, double * realv, char * charv, int format_len)
116 : {
117 : std::string message;
118 : unsigned int int_index = 0;
119 : unsigned int real_index = 0;
120 : unsigned int char_index = 0;
121 :
122 4398 : for (int i = 0; i < format_len; ++i)
123 : {
124 : // interpret %I, %R, and %S
125 4313 : if (format[i] == '%' && i < format_len - 1)
126 : {
127 595 : auto next = format[i + 1];
128 :
129 : // integer output
130 595 : if (next == 'I' || next == 'i')
131 : {
132 170 : message += std::to_string(intv[int_index++]);
133 170 : i++;
134 170 : continue;
135 : }
136 :
137 : // Real output
138 425 : if (next == 'R' || next == 'r')
139 : {
140 255 : message += std::to_string(realv[real_index++]);
141 255 : i++;
142 255 : continue;
143 : }
144 :
145 : // char[8] output
146 170 : if (next == 'S' || next == 's')
147 : {
148 1530 : for (unsigned int j = 0; j < 8; ++j)
149 1360 : message += charv[char_index++];
150 170 : i++;
151 170 : continue;
152 170 : }
153 : }
154 :
155 : // append character to string
156 3718 : message += format[i];
157 : }
158 :
159 : // output at the selected error level
160 85 : switch (*lop)
161 : {
162 : case 1:
163 108 : Moose::out << moose::internal::mooseMsgFmt(message, "** Abaqus Info **", COLOR_CYAN)
164 : << std::flush;
165 54 : break;
166 :
167 : case -1:
168 12 : Moose::out << moose::internal::mooseMsgFmt(message, "** Abaqus Warning **", COLOR_YELLOW)
169 : << std::flush;
170 6 : break;
171 :
172 : case -2:
173 48 : Moose::out << moose::internal::mooseMsgFmt(message, "** Abaqus Non-fatal Error **", COLOR_RED)
174 : << std::flush;
175 24 : break;
176 :
177 1 : case -3:
178 1 : mooseError(message);
179 : break;
180 :
181 0 : default:
182 0 : mooseError("Invalid LOP code passed to STDB_ABQERR: ", *lop);
183 : break;
184 : }
185 84 : }
186 :
187 : void
188 36 : AbaqusUtils::smaInitialize()
189 : {
190 : static bool initialized = false;
191 :
192 : // Guard the initialization with a double checked lock
193 36 : if (!initialized)
194 : {
195 : Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
196 18 : if (!initialized)
197 : {
198 6 : const auto n = getnumthreads_();
199 6 : _sma_local_int_array.resize(n);
200 6 : _sma_local_float_array.resize(n);
201 6 : initialized = true;
202 : }
203 : }
204 36 : }
205 :
206 : // Array creation
207 :
208 : std::map<int, std::vector<int>> AbaqusUtils::_sma_int_array;
209 : std::map<int, std::vector<Real>> AbaqusUtils::_sma_float_array;
210 : std::vector<std::map<int, std::vector<int>>> AbaqusUtils::_sma_local_int_array;
211 : std::vector<std::map<int, std::vector<Real>>> AbaqusUtils::_sma_local_float_array;
212 :
213 : extern "C" int *
214 3 : SMAIntArrayCreate(int id, int len, int val)
215 : {
216 3 : auto ib = AbaqusUtils::_sma_int_array.emplace(id, std::vector<int>(len, val));
217 3 : if (ib.second == false)
218 0 : mooseError("Error creating threaded storage in SMAIntArrayCreate");
219 3 : return ib.first->second.data();
220 : }
221 :
222 : extern "C" double *
223 3 : SMAFloatArrayCreate(int id, int len, Real val)
224 : {
225 3 : auto ib = AbaqusUtils::_sma_float_array.emplace(id, std::vector<Real>(len, val));
226 3 : if (ib.second == false)
227 0 : mooseError("Error creating threaded storage in SMAFloatArrayCreate");
228 3 : return ib.first->second.data();
229 : }
230 :
231 : extern "C" int *
232 18 : SMALocalIntArrayCreate(int id, int len, int val)
233 : {
234 18 : AbaqusUtils::smaInitialize();
235 18 : auto & array = AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_int_array,
236 18 : "SMALocalIntArrayCreate")[id];
237 18 : array.assign(len, val);
238 18 : return array.data();
239 : }
240 :
241 : extern "C" double *
242 18 : SMALocalFloatArrayCreate(int id, int len, Real val)
243 : {
244 18 : AbaqusUtils::smaInitialize();
245 18 : auto & array = AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_float_array,
246 18 : "SMALocalFloatArrayCreate")[id];
247 18 : array.assign(len, val);
248 18 : return array.data();
249 : }
250 :
251 : // Array access
252 :
253 : extern "C" int *
254 12 : SMAIntArrayAccess(int id)
255 : {
256 24 : auto it = AbaqusUtils::getSMAIterator(AbaqusUtils::_sma_int_array, id, "SMAIntArrayAccess");
257 12 : return it->second.data();
258 : }
259 :
260 : extern "C" double *
261 12 : SMAFloatArrayAccess(int id)
262 : {
263 24 : auto it = AbaqusUtils::getSMAIterator(AbaqusUtils::_sma_float_array, id, "SMAFloatArrayAccess");
264 12 : return it->second.data();
265 : }
266 :
267 : extern "C" int *
268 72 : SMALocalIntArrayAccess(int id)
269 : {
270 : auto & array =
271 72 : AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_int_array, "SMALocalIntArrayAccess");
272 144 : auto it = AbaqusUtils::getSMAIterator(array, id, "SMALocalIntArrayAccess");
273 72 : return it->second.data();
274 : }
275 :
276 : extern "C" double *
277 72 : SMALocalFloatArrayAccess(int id)
278 : {
279 72 : auto & array = AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_float_array,
280 : "SMALocalFloatArrayAccess");
281 144 : auto it = AbaqusUtils::getSMAIterator(array, id, "SMALocalFloatArrayAccess");
282 72 : return it->second.data();
283 : }
284 :
285 : // Array size check
286 :
287 : extern "C" std::size_t
288 363 : SMAIntArraySize(int id)
289 : {
290 726 : auto it = AbaqusUtils::getSMAIterator(AbaqusUtils::_sma_int_array, id, "SMAIntArraySize");
291 363 : return it->second.size();
292 : }
293 :
294 : extern "C" std::size_t
295 57 : SMAFloatArraySize(int id)
296 : {
297 114 : auto it = AbaqusUtils::getSMAIterator(AbaqusUtils::_sma_float_array, id, "SMAFloatArraySize");
298 57 : return it->second.size();
299 : }
300 :
301 : extern "C" std::size_t
302 2166 : SMALocalIntArraySize(int id)
303 : {
304 : auto & array =
305 2166 : AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_int_array, "SMALocalIntArraySize");
306 4332 : auto it = AbaqusUtils::getSMAIterator(array, id, "SMALocalIntArraySize");
307 2166 : return it->second.size();
308 : }
309 :
310 : extern "C" std::size_t
311 330 : SMALocalFloatArraySize(int id)
312 : {
313 : auto & array =
314 330 : AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_float_array, "SMALocalFloatArraySize");
315 660 : auto it = AbaqusUtils::getSMAIterator(array, id, "SMALocalFloatArraySize");
316 330 : return it->second.size();
317 : }
318 :
319 : // Array deletion
320 :
321 : extern "C" void
322 3 : SMAIntArrayDelete(int id)
323 : {
324 6 : auto it = AbaqusUtils::getSMAIterator(AbaqusUtils::_sma_int_array, id, "SMAIntArrayDelete");
325 3 : AbaqusUtils::_sma_int_array.erase(it);
326 3 : }
327 :
328 : extern "C" void
329 3 : SMAFloatArrayDelete(int id)
330 : {
331 6 : auto it = AbaqusUtils::getSMAIterator(AbaqusUtils::_sma_float_array, id, "SMAFloatArrayDelete");
332 3 : AbaqusUtils::_sma_float_array.erase(it);
333 3 : }
334 :
335 : extern "C" void
336 18 : SMALocalIntArrayDelete(int id)
337 : {
338 : auto & array =
339 18 : AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_int_array, "SMALocalIntArrayDelete");
340 36 : auto it = AbaqusUtils::getSMAIterator(array, id, "SMALocalIntArrayDelete");
341 18 : array.erase(it);
342 18 : }
343 :
344 : extern "C" void
345 18 : SMALocalFloatArrayDelete(int id)
346 : {
347 18 : auto & array = AbaqusUtils::getSMAThreadArray(AbaqusUtils::_sma_local_float_array,
348 : "SMALocalFloatArrayDelete");
349 36 : auto it = AbaqusUtils::getSMAIterator(array, id, "SMALocalFloatArrayDelete");
350 18 : array.erase(it);
351 18 : }
352 :
353 : // Mutex handling
354 :
355 : std::array<std::unique_ptr<Threads::spin_mutex>, 101> AbaqusUtils::_mutex = {{nullptr}};
356 :
357 : void
358 21 : AbaqusUtils::mutexInit(std::size_t n)
359 : {
360 : // Guard the initialization with a double checked lock
361 21 : if (!_mutex[n])
362 : {
363 : Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
364 20 : if (!_mutex[n])
365 18 : _mutex[n] = std::make_unique<Threads::spin_mutex>();
366 : }
367 21 : }
368 :
369 : void
370 21021 : AbaqusUtils::mutexLock(std::size_t n)
371 : {
372 21021 : if (n >= _mutex.size() || !_mutex[n])
373 0 : mooseError("Invalid or uninitialized mutex ", n);
374 : _mutex[n]->lock();
375 21021 : }
376 :
377 : void
378 21021 : AbaqusUtils::mutexUnlock(std::size_t n)
379 : {
380 21021 : if (n >= _mutex.size() || !_mutex[n])
381 0 : mooseError("Invalid or uninitialized mutex ", n);
382 : _mutex[n]->unlock();
383 21021 : }
384 :
385 : extern "C" void
386 21 : MutexInit(int id)
387 : {
388 21 : AbaqusUtils::mutexInit(id);
389 21 : }
390 :
391 : extern "C" void
392 21021 : MutexLock(int id)
393 : {
394 21021 : AbaqusUtils::mutexLock(id);
395 21021 : }
396 :
397 : extern "C" void
398 21021 : MutexUnlock(int id)
399 : {
400 21021 : AbaqusUtils::mutexUnlock(id);
401 21021 : }
|