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