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