1 /*!
2 * \file umat.cpp
3 * \brief
4 * \author Thomas Helfer
5 * \date 21/03/2016
6 */
7
8 #include<iostream>
9 #include<cstdlib>
10
11 #include<map>
12 #include<string>
13 #include<cctype>
14 #include<vector>
15 #include<utility>
16 #include<cstring>
17 #include<stdexcept>
18 #include<algorithm>
19
20 #if __cplusplus >= 201103L
21 #include<mutex>
22 #define HAVE_STD_MUTEX
23 #define NULLPTR(X) nullptr
24 #else /* __cplusplus >= 201103L */
25 #define NULLPTR(X) static_cast<X>(0)
26 #endif /* __cplusplus >= 201103L */
27
28 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
29 #ifndef NOMINMAX
30 #define NOMINMAX
31 #endif
32 #include<windows.h>
33 #ifdef min
34 #undef min
35 #endif
36
37 #ifdef max
38 #undef max
39 #endif
40 typedef HINSTANCE__* libptr;
41
42 #ifndef HAVE_STD_MUTEX
43
44 struct Mutex
45 {
getMutexMutex46 static Mutex& getMutex(){
47 static Mutex m;
48 return m;
49 }
50 HANDLE m;
51 private:
MutexMutex52 Mutex(){
53 this->m = CreateMutex(NULL, // default security attributes
54 FALSE, // initially not owned
55 NULL); // unnamed mutex
56 }
57 };
58
59 struct lock
60 {
locklock61 lock(){
62 DWORD r = WaitForSingleObject(Mutex::getMutex().m,
63 INFINITE);
64 if(r==WAIT_ABANDONED){
65 std::cerr << "umat: abandonned mutex" << std::endl;
66 std::exit(EXIT_FAILURE);
67 }
68 }
~locklock69 ~lock(){
70 CloseHandle(Mutex::getMutex().m);
71 }
72 };
73 #endif /* HAVE_STD_MUTEX */
74
75 // code retrieved from
76 // http://www.codeproject.com/Tips/479880/GetLastError-as-std-string
getLastWin32Error()77 static std::string getLastWin32Error()
78 {
79 const DWORD error = GetLastError();
80 if (error){
81 LPVOID lpMsgBuf;
82 DWORD bufLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
83 FORMAT_MESSAGE_FROM_SYSTEM |
84 FORMAT_MESSAGE_IGNORE_INSERTS,
85 NULL,error,
86 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
87 (LPTSTR) &lpMsgBuf,0,NULL );
88 if (bufLen){
89 LPCSTR lpMsgStr = (LPTSTR) lpMsgBuf;
90 std::string result(lpMsgStr, lpMsgStr+bufLen);
91 LocalFree(lpMsgBuf);
92 return result;
93 }
94 }
95 return std::string();
96 }
97
98 #else
99 #include<dlfcn.h>
100 typedef void * libptr;
101 #ifndef HAVE_STD_MUTEX
102 #error "Unsupported platform"
103 #endif /* HAVE_STD_MUTEX */
104 #endif
105
106 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
107 #define UMATFCT umat
108 #define UMATFCT2 umat2
109 #else
110 #define UMATFCT umat_
111 #define UMATFCT2 umat2_
112 #endif
113
114 #if (defined _WIN32) && (!defined _WIN64)
115 typedef int fortran_string_size;
116 #elif defined _WIN64
117 typedef size_t fortran_string_size;
118 #else
119 typedef int fortran_string_size;
120 #endif
121
122 typedef double abaqus_real;
123 typedef int abaqus_int;
124
125 typedef void (*umatptr)(abaqus_real *const,
126 abaqus_real *const,
127 abaqus_real *const,
128 abaqus_real *const,
129 abaqus_real *const,
130 abaqus_real *const,
131 abaqus_real *const,
132 abaqus_real *const,
133 abaqus_real *const,
134 abaqus_real *const,
135 const abaqus_real *const,
136 const abaqus_real *const,
137 const abaqus_real *const,
138 const abaqus_real *const,
139 const abaqus_real *const,
140 const abaqus_real *const,
141 const abaqus_real *const,
142 const abaqus_real *const,
143 const char *const,
144 const abaqus_int *const,
145 const abaqus_int *const,
146 const abaqus_int *const,
147 const abaqus_int *const,
148 const abaqus_real *const,
149 const abaqus_int *const,
150 const abaqus_real *const,
151 const abaqus_real *const,
152 abaqus_real *const,
153 const abaqus_real *const,
154 const abaqus_real *const,
155 const abaqus_real *const,
156 const abaqus_int *const,
157 const abaqus_int *const,
158 const abaqus_int *const,
159 const abaqus_int *const,
160 const abaqus_int *const,
161 abaqus_int *const,
162 const int);
163
164 extern "C" {
165 void UMATFCT(abaqus_real *const,
166 abaqus_real *const,
167 abaqus_real *const,
168 abaqus_real *const,
169 abaqus_real *const,
170 abaqus_real *const,
171 abaqus_real *const,
172 abaqus_real *const,
173 abaqus_real *const,
174 abaqus_real *const,
175 const abaqus_real *const,
176 const abaqus_real *const,
177 const abaqus_real *const,
178 const abaqus_real *const,
179 const abaqus_real *const,
180 const abaqus_real *const,
181 const abaqus_real *const,
182 const abaqus_real *const,
183 const char *const,
184 const abaqus_int *const,
185 const abaqus_int *const,
186 const abaqus_int *const,
187 const abaqus_int *const,
188 const abaqus_real *const,
189 const abaqus_int *const,
190 const abaqus_real *const,
191 const abaqus_real *const,
192 abaqus_real *const,
193 const abaqus_real *const,
194 const abaqus_real *const,
195 const abaqus_real *const,
196 const abaqus_int *const,
197 const abaqus_int *const,
198 const abaqus_int *const,
199 const abaqus_int *const,
200 const abaqus_int *const,
201 abaqus_int *const,
202 const fortran_string_size);
203
204 void UMATFCT2(abaqus_real *const,
205 abaqus_real *const,
206 abaqus_real *const,
207 abaqus_real *const,
208 abaqus_real *const,
209 abaqus_real *const,
210 abaqus_real *const,
211 abaqus_real *const,
212 abaqus_real *const,
213 abaqus_real *const,
214 const abaqus_real *const,
215 const abaqus_real *const,
216 const abaqus_real *const,
217 const abaqus_real *const,
218 const abaqus_real *const,
219 const abaqus_real *const,
220 const abaqus_real *const,
221 const abaqus_real *const,
222 const char *const,
223 const abaqus_int *const,
224 const abaqus_int *const,
225 const abaqus_int *const,
226 const abaqus_int *const,
227 const abaqus_real *const,
228 const abaqus_int *const,
229 const abaqus_real *const,
230 const abaqus_real *const,
231 abaqus_real *const,
232 const abaqus_real *const,
233 const abaqus_real *const,
234 const abaqus_real *const,
235 const abaqus_int *const,
236 const abaqus_int *const,
237 const abaqus_int *const,
238 const abaqus_int *const,
239 const abaqus_int *const,
240 abaqus_int *const,
241 const fortran_string_size);
242 }
243
244 struct LibrariesHandler
245 : public std::map<std::string,libptr>
246 {
~LibrariesHandlerLibrariesHandler247 ~LibrariesHandler(){
248 for(iterator pl=this->begin();pl!=this->end();++pl){
249 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
250 ::FreeLibrary(pl->second);
251 #else
252 ::dlclose(pl->second);
253 #endif
254 }
255 } // end of ~LibrariesHandler
256 }; // end of LibrariesHandler
257
258 struct UmatPtrHandler
259 {
260 std::string name;
261 umatptr ptr;
262 }; // end of UmatPtrHandler
263
report(const std::string & ln,const std::string & fn,const std::string & en,const char * const n)264 static void report(const std::string& ln,
265 const std::string& fn,
266 const std::string& en,
267 const char * const n){
268 std::cerr << "umat::load : could not load behaviour '"
269 << std::string(n,n+80) << '\'';
270 if(!ln.empty()){
271 std::cerr << "\nTried library '" << ln << '\'';
272 }
273 if(!fn.empty()){
274 std::cerr << "\nTried function '" << fn << '\'';
275 }
276 if(!en.empty()){
277 std::cerr << '\n' << en;
278 }
279 std::cerr << std::endl;
280 }
281
282 struct UMATNameCompare
283 {
UMATNameCompareUMATNameCompare284 UMATNameCompare(const char* const s)
285 : n(s)
286 {} // end of UMATNameCompare
UMATNameCompareUMATNameCompare287 UMATNameCompare(const UMATNameCompare &p)
288 : n(p.n)
289 {}
operator ()UMATNameCompare290 bool operator()(const UmatPtrHandler& h) const{
291 return ::strncmp(h.name.data(),n,std::min(h.name.size(),
292 std::string::size_type(79)))==0;
293 }
294 private:
295 const char* const n;
296 };
error_msg(const char * const msg)297 static void error_msg(const char* const msg){
298 std::cerr << "umat: " << msg << std::endl;
299 }
300
extract(const char * & p,const char * const pe,const char * const msg)301 static std::string extract(const char*& p,
302 const char* const pe,
303 const char* const msg)
304 {
305 if(p==pe){
306 error_msg(msg);
307 return "";
308 }
309 const char* const n = std::find(p,pe,'_');
310 if(n==p){
311 error_msg(msg);
312 return "";
313 }
314 std::string r = std::string(p,n);
315 p=n;
316 return r;
317 }
318
decompose(const char * const n)319 static std::pair<std::string,std::string> decompose(const char * const n)
320 {
321 const char* pn = n;
322 const char* pne = n+80;
323 // removing spaces at the end
324 while((pne!=pn)&&((std::isspace(*(pne-1)))||(*(pne-1)=='\0'))){
325 --pne;
326 }
327 if(pn==pne){
328 error_msg("empty string");
329 return std::make_pair(std::string(),std::string());
330 };
331 const std::string ln = extract(pn,pne,"can't extract library name");
332 #ifdef _WIN32
333 std::string lib = "lib" + ln + ".dll";
334 #else
335 std::string lib = "lib" + ln + ".so";
336 #endif
337 if(pn==pne){
338 error_msg("extract function name");
339 return std::make_pair(std::string(),std::string());
340 }
341 ++pn;
342 std::string fct = extract(pn,pne,"can't extract function name");
343 if(fct.empty()){
344 return std::make_pair(std::string(),std::string());
345 }
346 if(pn!=pne){
347 ++pn;
348 fct += '_'+extract(pn,pne,"can't extract hypothesis");
349 }
350 #ifdef MFRONT_UMAT_DEBUG
351 std::cout << "library: " << lib << std::endl;
352 std::cout << "behaviour: " << fct << std::endl;
353 if(pn!=pne){
354 ++pn;
355 if(pn!=pne){
356 std::cout << "suffix: '" << std::string(pn,pne) << "'" << std::endl;
357 }
358 }
359 #endif /* MFRONT_UMAT_DEBUG */
360 return std::make_pair(lib,fct);
361 }
362
load(const char * n)363 static umatptr load(const char* n){
364 typedef std::vector<UmatPtrHandler> UmatPtrContainer;
365 static LibrariesHandler libraries;
366 static UmatPtrContainer fcts;
367 #ifdef HAVE_STD_MUTEX
368 static std::mutex m;
369 std::lock_guard<std::mutex> lock(m);
370 #else /* HAVE_STD_MUTEX */
371 lock l;
372 #endif /* HAVE_STD_MUTEX */
373 try{
374 UmatPtrContainer::const_iterator p;
375 p = std::find_if(fcts.begin(),fcts.end(),UMATNameCompare(n));
376 if(p==fcts.end()){
377 const std::pair<std::string,std::string> lf = decompose(n);
378 const std::string& lib = lf.first;
379 const std::string& fct = lf.second;
380 if(lib.empty()){
381 report("","","",n);
382 return NULLPTR(umatptr);
383 }
384 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
385 libptr l = ::LoadLibrary(TEXT (lib.c_str()));
386 #else
387 libptr l = ::dlopen(lib.c_str(),RTLD_NOW);
388 #endif
389 if(l==NULLPTR(libptr)){
390 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
391 report(lib,"",getLastWin32Error(),n);
392 #else
393 report(lib,"",::dlerror(),n);
394 #endif
395 return NULLPTR(umatptr);
396 }
397 libraries.insert(std::make_pair(lib,l));
398 union {
399 void *ptr;
400 umatptr f;
401 } r;
402 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
403 r.f = reinterpret_cast<umatptr>(::GetProcAddress(l,fct.c_str()));
404 #else
405 r.ptr = ::dlsym(l,fct.c_str());
406 #endif
407 if(r.ptr==NULLPTR(void *)){
408 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
409 report(lib,fct,getLastWin32Error(),n);
410 #else
411 report(lib,fct,::dlerror(),n);
412 #endif
413 return NULLPTR(umatptr);
414 }
415 UmatPtrHandler h;
416 h.name = std::string(n,n+80);
417 h.ptr = r.f;
418 fcts.push_back(h);
419 return r.f;
420 }
421 return p->ptr;
422 }
423 catch(const std::exception& e){
424 std::cerr << "umat::load : " << e.what() << std::endl;
425 }
426 catch(...){
427 std::cerr << "umat::load : unknown exception" << std::endl;
428 }
429 return NULLPTR(umatptr);
430 }
431
432 extern "C" {
433
UMATFCT(abaqus_real * const STRESS,abaqus_real * const STATEV,abaqus_real * const DDSDDE,abaqus_real * const SSE,abaqus_real * const SPD,abaqus_real * const SCD,abaqus_real * const RPL,abaqus_real * const DDSDDT,abaqus_real * const DRPLDE,abaqus_real * const DRPLDT,const abaqus_real * const STRAN,const abaqus_real * const DSTRAN,const abaqus_real * const TIME,const abaqus_real * const DTIME,const abaqus_real * const TEMP,const abaqus_real * const DTEMP,const abaqus_real * const PREDEF,const abaqus_real * const DPRED,const char * const CMNAME,const abaqus_int * const NDI,const abaqus_int * const NSHR,const abaqus_int * const NTENS,const abaqus_int * const NSTATV,const abaqus_real * const PROPS,const abaqus_int * const NPROPS,const abaqus_real * const COORDS,const abaqus_real * const DROT,abaqus_real * const PNEWDT,const abaqus_real * const CELENT,const abaqus_real * const DFGRD0,const abaqus_real * const DFGRD1,const abaqus_int * const NOEL,const abaqus_int * const NPT,const abaqus_int * const LAYER,const abaqus_int * const KSPT,const abaqus_int * const KSTEP,abaqus_int * const KINC,const fortran_string_size size)434 void UMATFCT(abaqus_real *const STRESS,
435 abaqus_real *const STATEV,
436 abaqus_real *const DDSDDE,
437 abaqus_real *const SSE,
438 abaqus_real *const SPD,
439 abaqus_real *const SCD,
440 abaqus_real *const RPL,
441 abaqus_real *const DDSDDT,
442 abaqus_real *const DRPLDE,
443 abaqus_real *const DRPLDT,
444 const abaqus_real *const STRAN,
445 const abaqus_real *const DSTRAN,
446 const abaqus_real *const TIME,
447 const abaqus_real *const DTIME,
448 const abaqus_real *const TEMP,
449 const abaqus_real *const DTEMP,
450 const abaqus_real *const PREDEF,
451 const abaqus_real *const DPRED,
452 const char *const CMNAME,
453 const abaqus_int *const NDI,
454 const abaqus_int *const NSHR,
455 const abaqus_int *const NTENS,
456 const abaqus_int *const NSTATV,
457 const abaqus_real *const PROPS,
458 const abaqus_int *const NPROPS,
459 const abaqus_real *const COORDS,
460 const abaqus_real *const DROT,
461 abaqus_real *const PNEWDT,
462 const abaqus_real *const CELENT,
463 const abaqus_real *const DFGRD0,
464 const abaqus_real *const DFGRD1,
465 const abaqus_int *const NOEL,
466 const abaqus_int *const NPT,
467 const abaqus_int *const LAYER,
468 const abaqus_int *const KSPT,
469 const abaqus_int *const KSTEP,
470 abaqus_int *const KINC,
471 const fortran_string_size size){
472 umatptr f = load(CMNAME);
473 if(f!=NULLPTR(umatptr)){
474 f(STRESS,STATEV,DDSDDE,SSE,SPD,SCD,RPL,
475 DDSDDT,DRPLDE,DRPLDT,STRAN,DSTRAN,TIME,
476 DTIME,TEMP,DTEMP,PREDEF,DPRED,CMNAME,
477 NDI,NSHR,NTENS,NSTATV,PROPS,NPROPS,
478 COORDS,DROT,PNEWDT,CELENT,DFGRD0,DFGRD1,
479 NOEL,NPT,LAYER,KSPT,KSTEP,KINC,size);
480 return;
481 }
482
483 /*
484 * by default, we fail if we could not load an external function
485 */
486
487 std::cout << "umat : unsupported material" << std::endl;
488 ::exit(-1);
489
490 /*
491 * However, if we want to combine mfront laws and standard umat,
492 * it is possible:
493 * - just rename your standard umat subroutine in umat2
494 * - comment the two previous lines
495 * - uncomment the newt lines
496 */
497
498 // UMATFCT2(STRESS,STATEV,DDSDDE,SSE,SPD,SCD,RPL,
499 // DDSDDT,DRPLDE,DRPLDT,STRAN,DSTRAN,TIME,
500 // DTIME,TEMP,DTEMP,PREDEF,DPRED,CMNAME,
501 // NDI,NSHR,NTENS,NSTATV,PROPS,NPROPS,
502 // COORDS,DROT,PNEWDT,CELENT,DFGRD0,DFGRD1,
503 // NOEL,NPT,LAYER,KSPT,KSTEP,KINC,size);
504
505 } // end of umat_
506
507 } // end of extern "C"
508
509 // int main(void){
510 // char n[80] = {'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
511 // '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
512 // '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
513 // '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
514 // '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
515 // '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
516 // '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
517 // '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
518 // const char * b = "UMATBEHAVIOUR_CHABOCHE_3D_1";
519 // std::copy(b,b+std::strlen(b),n);
520 // std::pair<std::string,std::string> r = decompose(n);
521 // std::cout << r.first << std::endl;
522 // std::cout << r.second << std::endl;
523 // std::fill(n,n+80,'\0');
524 // const char * b2 = "UMATBEHAVIOUR_CHABOCHE_PSTRAIN";
525 // std::copy(b2,b2+std::strlen(b2),n);
526 // r = decompose(n);
527 // std::cout << r.first << std::endl;
528 // std::cout << r.second << std::endl;
529 // std::fill(n,n+80,'\0');
530 // r = decompose(n);
531 // std::cout << r.first << std::endl;
532 // std::cout << r.second << std::endl;
533 // return 0;
534 // }
535