1 /*!
2 * \file vumat-dp.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 << "vumat: 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 VUMATFCT vumat
108 #define VUMATFCT2 vumat2
109 #else
110 #define VUMATFCT vumat_
111 #define VUMATFCT2 vumat2_
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 float abaqus_real;
123 typedef int abaqus_int;
124
125 typedef void (*vumatptr)(const abaqus_int *const,
126 const abaqus_int *const,
127 const abaqus_int *const,
128 const abaqus_int *const,
129 const abaqus_int *const,
130 const abaqus_int *const,
131 const abaqus_int *const,
132 const abaqus_real* const,
133 const abaqus_real* const,
134 const abaqus_real* const,
135 const char* 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 abaqus_real* const,
144 const abaqus_real* const,
145 const abaqus_real* const,
146 const abaqus_real* const,
147 const abaqus_real* const,
148 const abaqus_real* const,
149 const abaqus_real* const,
150 const abaqus_real* const,
151 const abaqus_real* const,
152 const abaqus_real* const,
153 const abaqus_real* const,
154 const abaqus_real*,
155 const abaqus_real*,
156 const abaqus_real*,
157 const abaqus_real*,
158 const fortran_string_size);
159
160 extern "C" {
161 void VUMATFCT(const abaqus_int *const,
162 const abaqus_int *const,
163 const abaqus_int *const,
164 const abaqus_int *const,
165 const abaqus_int *const,
166 const abaqus_int *const,
167 const abaqus_int *const,
168 const abaqus_real* const,
169 const abaqus_real* const,
170 const abaqus_real* const,
171 const char* const,
172 const abaqus_real* const,
173 const abaqus_real* const,
174 const 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 abaqus_real* const,
184 const abaqus_real* const,
185 const abaqus_real* const,
186 const abaqus_real* const,
187 const abaqus_real* const,
188 const abaqus_real* const,
189 const abaqus_real* const,
190 const abaqus_real*,
191 const abaqus_real*,
192 const abaqus_real*,
193 const abaqus_real*,
194 const fortran_string_size);
195
196 void VUMATFCT2(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 const abaqus_int *const,
202 const abaqus_int *const,
203 const abaqus_real* const,
204 const abaqus_real* const,
205 const abaqus_real* const,
206 const char* const,
207 const abaqus_real* const,
208 const abaqus_real* const,
209 const abaqus_real* const,
210 const abaqus_real* const,
211 const abaqus_real* const,
212 const abaqus_real* const,
213 const 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 abaqus_real* const,
223 const abaqus_real* const,
224 const abaqus_real* const,
225 const abaqus_real*,
226 const abaqus_real*,
227 const abaqus_real*,
228 const abaqus_real*,
229 const fortran_string_size);
230 }
231
232 struct LibrariesHandler
233 : public std::map<std::string,libptr>
234 {
~LibrariesHandlerLibrariesHandler235 ~LibrariesHandler(){
236 for(iterator pl=this->begin();pl!=this->end();++pl){
237 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
238 ::FreeLibrary(pl->second);
239 #else
240 ::dlclose(pl->second);
241 #endif
242 }
243 } // end of ~LibrariesHandler
244 }; // end of LibrariesHandler
245
246 struct VUMATPtrHandler
247 {
248 std::string name;
249 vumatptr ptr;
250 }; // end of VUMATPtrHandler
251
report(const std::string & ln,const std::string & fn,const std::string & en,const char * const n)252 static void report(const std::string& ln,
253 const std::string& fn,
254 const std::string& en,
255 const char * const n){
256 std::cerr << "vumat::load : could not load behaviour '"
257 << std::string(n,n+80) << '\'';
258 if(!ln.empty()){
259 std::cerr << "\nTried library '" << ln << '\'';
260 }
261 if(!fn.empty()){
262 std::cerr << "\nTried function '" << fn << '\'';
263 }
264 if(!en.empty()){
265 std::cerr << '\n' << en;
266 }
267 std::cerr << std::endl;
268 }
269
270 struct VUMATNameCompare
271 {
VUMATNameCompareVUMATNameCompare272 VUMATNameCompare(const char* const s)
273 : n(s)
274 {} // end of VUMATNameCompare
VUMATNameCompareVUMATNameCompare275 VUMATNameCompare(const VUMATNameCompare &p)
276 : n(p.n)
277 {}
operator ()VUMATNameCompare278 bool operator()(const VUMATPtrHandler& h) const{
279 return ::strncmp(h.name.data(),n,std::min(h.name.size(),
280 std::string::size_type(79)))==0;
281 }
282 private:
283 const char* const n;
284 };
error_msg(const char * const msg)285 static void error_msg(const char* const msg){
286 std::cerr << "vumat: " << msg << std::endl;
287 }
288
extract(const char * & p,const char * const pe,const char * const msg)289 static std::string extract(const char*& p,
290 const char* const pe,
291 const char* const msg)
292 {
293 if(p==pe){
294 error_msg(msg);
295 return "";
296 }
297 const char* const n = std::find(p,pe,'_');
298 if(n==p){
299 error_msg(msg);
300 return "";
301 }
302 std::string r = std::string(p,n);
303 p=n;
304 return r;
305 }
306
decompose(const char * const n)307 static std::pair<std::string,std::string> decompose(const char * const n)
308 {
309 const char* pn = n;
310 const char* pne = n+80;
311 // removing spaces at the end
312 while((pne!=pn)&&((std::isspace(*(pne-1)))||(*(pne-1)=='\0'))){
313 --pne;
314 }
315 if(pn==pne){
316 error_msg("empty string");
317 return std::make_pair(std::string(),std::string());
318 };
319 const std::string ln = extract(pn,pne,"can't extract library name");
320 #ifdef _WIN32
321 std::string lib = "lib" + ln + ".dll";
322 #else
323 std::string lib = "lib" + ln + ".so";
324 #endif
325 if(pn==pne){
326 error_msg("extract function name");
327 return std::make_pair(std::string(),std::string());
328 }
329 ++pn;
330 std::string fct = extract(pn,pne,"can't extract function name");
331 if(fct.empty()){
332 return std::make_pair(std::string(),std::string());
333 }
334 if(pn!=pne){
335 ++pn;
336 fct += '_'+extract(pn,pne,"can't extract hypothesis");
337 }
338 fct += "_f"; // simple precision
339 #ifdef MFRONT_VUMAT_DEBUG
340 std::cout << "library: " << lib << std::endl;
341 std::cout << "behaviour: " << fct << std::endl;
342 if(pn!=pne){
343 ++pn;
344 if(pn!=pne){
345 std::cout << "suffix: '" << std::string(pn,pne) << "'" << std::endl;
346 }
347 }
348 #endif /* MFRONT_VUMAT_DEBUG */
349 return std::make_pair(lib,fct);
350 }
351
load(const char * n)352 static vumatptr load(const char* n){
353 typedef std::vector<VUMATPtrHandler> VUMATPtrContainer;
354 static LibrariesHandler libraries;
355 static VUMATPtrContainer fcts;
356 #ifdef HAVE_STD_MUTEX
357 static std::mutex m;
358 std::lock_guard<std::mutex> lock(m);
359 #else /* HAVE_STD_MUTEX */
360 lock l;
361 #endif /* HAVE_STD_MUTEX */
362 try{
363 VUMATPtrContainer::const_iterator p;
364 p = std::find_if(fcts.begin(),fcts.end(),VUMATNameCompare(n));
365 if(p==fcts.end()){
366 const std::pair<std::string,std::string> lf = decompose(n);
367 const std::string& lib = lf.first;
368 const std::string& fct = lf.second;
369 if(lib.empty()){
370 report("","","",n);
371 return NULLPTR(vumatptr);
372 }
373 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
374 libptr l = ::LoadLibrary(TEXT (lib.c_str()));
375 #else
376 libptr l = ::dlopen(lib.c_str(),RTLD_NOW);
377 #endif
378 if(l==NULLPTR(libptr)){
379 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
380 report(lib,"",getLastWin32Error(),n);
381 #else
382 report(lib,"",::dlerror(),n);
383 #endif
384 return NULLPTR(vumatptr);
385 }
386 libraries.insert(std::make_pair(lib,l));
387 union {
388 void *ptr;
389 vumatptr f;
390 } r;
391 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
392 r.f = reinterpret_cast<vumatptr>(::GetProcAddress(l,fct.c_str()));
393 #else
394 r.ptr = ::dlsym(l,fct.c_str());
395 #endif
396 if(r.ptr==NULLPTR(void *)){
397 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
398 report(lib,fct,getLastWin32Error(),n);
399 #else
400 report(lib,fct,::dlerror(),n);
401 #endif
402 return NULLPTR(vumatptr);
403 }
404 VUMATPtrHandler h;
405 h.name = std::string(n,n+80);
406 h.ptr = r.f;
407 fcts.push_back(h);
408 return r.f;
409 }
410 return p->ptr;
411 }
412 catch(const std::exception& e){
413 std::cerr << "vumat::load : " << e.what() << std::endl;
414 }
415 catch(...){
416 std::cerr << "vumat::load : unknown exception" << std::endl;
417 }
418 return NULLPTR(vumatptr);
419 }
420
421 extern "C" {
422
VUMATFCT(const abaqus_int * const nblock,const abaqus_int * const ndir,const abaqus_int * const nshr,const abaqus_int * const nstatev,const abaqus_int * const nfieldv,const abaqus_int * const nprops,const abaqus_int * const lanneal,const abaqus_real * const stepTime,const abaqus_real * const totalTime,const abaqus_real * const dt,const char * const cmname,const abaqus_real * const coordMp,const abaqus_real * const charLength,const abaqus_real * const props,const abaqus_real * const density,const abaqus_real * const strainInc,const abaqus_real * const relSpinInc,const abaqus_real * const tempOld,const abaqus_real * const stretchOld,const abaqus_real * const defgradOld,const abaqus_real * const fieldOld,const abaqus_real * const stressOld,const abaqus_real * const stateOld,const abaqus_real * const enerInternOld,const abaqus_real * const enerInelasOld,const abaqus_real * const tempNew,const abaqus_real * const stretchNew,const abaqus_real * const defgradNew,const abaqus_real * const fieldNew,const abaqus_real * stressNew,const abaqus_real * stateNew,const abaqus_real * enerInternNew,const abaqus_real * enerInelasNew,const fortran_string_size size)423 void VUMATFCT(const abaqus_int *const nblock,
424 const abaqus_int *const ndir,
425 const abaqus_int *const nshr,
426 const abaqus_int *const nstatev,
427 const abaqus_int *const nfieldv,
428 const abaqus_int *const nprops,
429 const abaqus_int * const lanneal,
430 const abaqus_real* const stepTime,
431 const abaqus_real* const totalTime,
432 const abaqus_real* const dt,
433 const char* const cmname,
434 const abaqus_real* const coordMp,
435 const abaqus_real* const charLength,
436 const abaqus_real* const props,
437 const abaqus_real* const density,
438 const abaqus_real* const strainInc,
439 const abaqus_real* const relSpinInc,
440 const abaqus_real* const tempOld,
441 const abaqus_real* const stretchOld,
442 const abaqus_real* const defgradOld,
443 const abaqus_real* const fieldOld,
444 const abaqus_real* const stressOld,
445 const abaqus_real* const stateOld,
446 const abaqus_real* const enerInternOld,
447 const abaqus_real* const enerInelasOld,
448 const abaqus_real* const tempNew,
449 const abaqus_real* const stretchNew,
450 const abaqus_real* const defgradNew,
451 const abaqus_real* const fieldNew,
452 const abaqus_real* stressNew,
453 const abaqus_real* stateNew,
454 const abaqus_real* enerInternNew,
455 const abaqus_real* enerInelasNew,
456 const fortran_string_size size){
457 const vumatptr f = load(cmname);
458 if(f!=NULLPTR(vumatptr)){
459 f(nblock,ndir,nshr,nstatev,nfieldv,nprops,
460 lanneal,stepTime,totalTime,dt,
461 cmname,coordMp,charLength,props,
462 density,strainInc,relSpinInc,tempOld,
463 stretchOld,defgradOld,fieldOld,stressOld,
464 stateOld,enerInternOld,enerInelasOld,tempNew,
465 stretchNew,defgradNew,fieldNew,stressNew,
466 stateNew,enerInternNew,enerInelasNew,size);
467 return;
468 }
469
470 /*
471 * by default, we fail if we could not load an external function
472 */
473
474 std::cout << "vumat : unsupported material" << std::endl;
475 ::exit(-1);
476
477 /*
478 * However, if we want to combine mfront laws and standard vumat,
479 * it is possible:
480 * - just rename your standard vumat subroutine in vumat2
481 * - comment the two previous lines
482 * - uncomment the newt lines
483 */
484
485 // VUMATFCT2(nblock,ndir,nshr,nstatev,nfieldv,nprops,
486 // lanneal,stepTime,totalTime,dt,
487 // cmname,coordMp,charLength,props,
488 // density,strainInc,relSpinInc,tempOld,
489 // stretchOld,defgradOld,fieldOld,stressOld,
490 // stateOld,enerInternOld,enerInelasOld,tempNew,
491 // stretchNew,defgradNew,fieldNew,stressNew,
492 // stateNew,enerInternNew,enerInelasNew,size);
493
494 } // end of vumat_
495
496 } // end of extern "C"
497