1 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
2 #include <windows.h>
3 #else /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
4 #include <dlfcn.h>
5 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
6 
7 #include <vector>
8 #include <string>
9 #include <cctype>
10 #include <cstdlib>
11 #include <sstream>
12 #include <fstream>
13 #include <iostream>
14 #include <algorithm>
15 
16 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
17 // code retrieved from
18 // http://www.codeproject.com/Tips/479880/GetLastError-as-std-string
getLastWin32Error()19 static std::string getLastWin32Error() {
20   const DWORD error = GetLastError();
21   if (error) {
22     LPVOID lpMsgBuf;
23     DWORD bufLen = FormatMessage(
24         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
25         nullptr, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr);
26     if (bufLen) {
27       LPCSTR lpMsgStr = (LPTSTR)lpMsgBuf;
28       std::string result(lpMsgStr, lpMsgStr + bufLen);
29       LocalFree(lpMsgBuf);
30       return result;
31     }
32   }
33   return std::string();
34 }
35 #endif /*  (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
36 
getErrorMessage()37 static std::string getErrorMessage() {
38 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
39   return getLastWin32Error();
40 #else
41   const auto e = ::dlerror();
42   if (e != nullptr) {
43     return std::string(e);
44   }
45   return "";
46 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
47 }  // end of  getErrorMessage
48 
usermat_log(const std::string & m)49 static void usermat_log(const std::string &m) {
50   static std::ofstream log("mfront-usermat.log");
51   log << m << std::endl;
52   std::clog << m << std::endl;
53 }
54 
tokenize(const std::string & s,const char c)55 static std::vector<std::string> tokenize(const std::string &s, const char c) {
56   std::vector<std::string> res;
57   std::string::size_type b = 0u;
58   std::string::size_type e = s.find_first_of(c, b);
59   while (std::string::npos != e || std::string::npos != b) {
60     // Found a token, add it to the vector.
61     res.push_back(s.substr(b, e - b));
62     b = s.find_first_not_of(c, e);
63     e = s.find_first_of(c, b);
64   }
65   return res;
66 }  // end of tokenize
67 
strim_front(const std::string & s)68 static std::string strim_front(const std::string &s) {
69   std::string::size_type b = 0u;
70   std::string::size_type e = s.size();
71   while (b != e) {
72     if (!std::isspace(s[b])) {
73       return s.substr(b);
74     }
75     ++b;
76   }
77   return "";
78 }
79 
strim_back(const std::string & s)80 static std::string strim_back(const std::string &s) {
81   std::string::size_type b = 0u;
82   std::string::size_type e = s.size();
83   while (b != e) {
84     if (std::isspace(s[b])) {
85       return s.substr(0, b);
86     }
87     ++b;
88   }
89   return s;
90 }
91 
strim(const std::string & s)92 static std::string strim(const std::string &s) {
93   return strim_front(strim_back(s));
94 }  // end of tokenize
95 
strim(const std::vector<std::string> & v)96 static std::vector<std::string> strim(const std::vector<std::string> &v) {
97   auto r = std::vector<std::string>{};
98   r.reserve(v.size());
99   for (const auto &s : v) {
100     auto ss = strim(s);
101     if (!ss.empty()) {
102       r.push_back(std::move(ss));
103     }
104   }
105   return r;
106 }  // end of tokenize
107 
usermat_exit(const std::string & m)108 static void usermat_exit(const std::string &m) {
109   usermat_log(m);
110 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
111   MessageBox(nullptr, m.c_str(), "mfront", 0);
112 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
113   std::exit(-1);
114 }  // end of usermat_exit
115 
116 namespace ansys {
117 
118   /*!
119    * structure in charge of associating a MFront behaviour to a
120    * material by reading the `mfront-usermat.dat` file in the current
121    * directory.
122    */
123   struct UserMaterialManager {
124     //! a simple alias
125     using AnsysIntegerType = int;
126     //! a simple alias
127     using AnsysRealType = double;
128     //! a simple alias
129     using AnsysFctPtr = void (*)(const AnsysIntegerType *const,
130                                  const AnsysIntegerType *const,
131                                  const AnsysIntegerType *const,
132                                  const AnsysIntegerType *const,
133                                  const AnsysIntegerType *const,
134                                  const AnsysIntegerType *const,
135                                  const AnsysIntegerType *const,
136                                  AnsysIntegerType *const,
137                                  const AnsysIntegerType *const,
138                                  const AnsysIntegerType *const,
139                                  const AnsysIntegerType *const,
140                                  const AnsysIntegerType *const,
141                                  const AnsysIntegerType *const,
142                                  const AnsysRealType *const,
143                                  const AnsysRealType *const,
144                                  const AnsysRealType *const,
145                                  const AnsysRealType *const,
146                                  AnsysRealType *const,
147                                  AnsysRealType *const,
148                                  AnsysRealType *const,
149                                  AnsysRealType *const,
150                                  AnsysRealType *const,
151                                  AnsysRealType *const,
152                                  const AnsysRealType *const,
153                                  const AnsysRealType *const,
154                                  AnsysRealType *const,
155                                  const AnsysRealType *const,
156                                  const AnsysRealType *const,
157                                  const AnsysRealType *const,
158                                  const AnsysRealType *const,
159                                  const AnsysRealType *const,
160                                  const AnsysRealType *const,
161                                  AnsysRealType *const,
162                                  const AnsysRealType *const,
163                                  const AnsysRealType *const,
164                                  const AnsysRealType *const,
165                                  const AnsysRealType *const,
166                                  const AnsysRealType *const,
167                                  const AnsysRealType *const,
168                                  const AnsysRealType *const,
169                                  const AnsysRealType *const);
170     //! default constructor
171     UserMaterialManager();
172     /*!
173      * \return the function associated to a material identifier
174      * \param[in] id: material identifier
175      */
176     AnsysFctPtr getBehaviour(const AnsysIntegerType) const;
177     //! destructor
178     ~UserMaterialManager();
179 
180    private:
181 //! a simple alias
182 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
183     using libhandler = HINSTANCE__ *;
184 #else /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
185     using libhandler = void *;
186 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
187        /*!
188         * \brief internal data structure storing pointers to MFront
189         * behaviour and the associated material identifier
190         */
191     struct UserMaterialHander {
192       //! material identifier
193       const int id;
194       //! pointer to the MFront behaviour
195       const AnsysFctPtr f;
196     };  // end of struct UserMaterialHander
197     //! internal data structure storing pointers to external libraries
198     struct ExternalLibraryHandler {
199       //! library name
200       const std::string name;
201       //! library handler
202       const libhandler l;
203     };  // end of struct ExternalLibraryHandler
204     //! list of all registred behaviours
205     std::vector<UserMaterialHander> handlers;
206     //! list of all loaded library
207     std::vector<ExternalLibraryHandler> libraries;
208     /* deleted methods */
209     UserMaterialManager(UserMaterialManager &&) = delete;
210     UserMaterialManager(const UserMaterialManager &) = delete;
211     UserMaterialManager &operator=(UserMaterialManager &&) = delete;
212     UserMaterialManager &operator=(const UserMaterialManager &) = delete;
213   };  // end of struct UserMaterialManager
214 
UserMaterialManager()215   UserMaterialManager::UserMaterialManager() {
216     auto find_library = [this](const std::string &n) {
217       return std::find_if(this->libraries.begin(), this->libraries.end(),
218                           [&n](const ExternalLibraryHandler &l) { return l.name == n; });
219     };
220     auto exit_if = [](const bool b, const std::string &m) {
221       if (b) {
222         usermat_exit("UserMaterialManager::UserMaterialManager: " + m);
223       }
224     };
225     auto emsg = std::string{};
226     auto open_library = [&emsg](const std::string &lib) -> libhandler {
227 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
228       for (const auto prefix : {"", "lib"}) {
229         for (const auto suffix : {"", ".dll"}) {
230           const auto library = prefix + lib + suffix;
231           const auto l = ::LoadLibrary(TEXT(library.c_str()));
232           if (l != nullptr) {
233             return l;
234           } else {
235 	    emsg += "UserMaterialManager::UserMaterialManager: "
236 	    "failed to open library '"+
237 	    library + "' (" + getErrorMessage() + ")\n";
238           }
239         }
240       }
241 #else  /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
242       for (const auto prefix : {"", "lib"}) {
243         for (const auto suffix : {"", ".so", ".dylib"}) {
244           const auto library = prefix + lib + suffix;
245           const auto l = ::dlopen(library.c_str(), RTLD_NOW);
246           if (l != nullptr) {
247             return l;
248           } else {
249             emsg += "UserMaterialManager::UserMaterialManager: "
250 	    "failed to open library '" +
251 	    library + "' (" + getErrorMessage() + ")\n";
252           }
253         }
254       }
255 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
256       return nullptr;
257     };
258     std::ifstream in("mfront-usermat.dat");
259     exit_if(!in, "unable to open file 'mfront-usermat.dat'");
260     std::string line;
261     size_t ln = 1u;
262     while (getline(in, line)) {
263       auto tokens = strim(tokenize(line, ','));
264       if ((tokens.empty()) || (tokens[0] == "/com")) {
265         ++ln;
266         continue;
267       }
268       exit_if(tokens.size() != 5, "invalid line '" + std::to_string(ln) +
269                                       "' in file 'mfront-usermat.dat', "
270                                       "expected at least 5 tokens");
271       exit_if(tokens[0] != "tb", "invalid line, expected 'tb', read '"+tokens[0]+"'");
272       exit_if(tokens[1] != "mfront", "invalid line '" + std::to_string(ln) +
273                                          "' in file 'mfront-usermat.dat', "
274                                          "expected 'mfront', read '" +
275                                          tokens[1] + "'");
276       const auto id = std::stoi(tokens[2]);
277       const auto lib = tokens[3];
278       const auto fct = tokens[4];
279       usermat_log(
280           "UserMaterialManager::UserMaterialManager: "
281           "associating material '" +
282           std::to_string(id) + "' to behaviour '" + fct + "' in library '" + lib);
283       exit_if(this->getBehaviour(id) != nullptr,
284               "a behaviour has already been associated to material "
285               "identifier '" + std::to_string(id) + "'");
286       auto ptr = find_library(lib);
287       if (ptr == this->libraries.end()) {
288         const auto l = open_library(lib);
289         exit_if(l == nullptr, "unable to load library '" + lib + "'\n"+emsg);
290         this->libraries.push_back(ExternalLibraryHandler{lib, l});
291         ptr = std::prev(this->libraries.end());
292       }
293 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
294       auto f = reinterpret_cast<AnsysFctPtr>(::GetProcAddress(ptr->l, fct.c_str()));
295 #else  /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
296       auto f = reinterpret_cast<AnsysFctPtr>(::dlsym(ptr->l, fct.c_str()));
297 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
298       exit_if(f == nullptr, "could not load behaviour '" + fct + "' in library '" + lib + "' (" +
299                                 getErrorMessage() + ")");
300       this->handlers.push_back(std::move(UserMaterialHander{id, f}));
301       ++ln;
302     }
303     exit_if(in.bad(), "error while reading file 'mfront-usermat.dat'");
304     in.close();
305   }  // end of UserMaterialManager::UserMaterialManager
306 
getBehaviour(const AnsysIntegerType id) const307   UserMaterialManager::AnsysFctPtr UserMaterialManager::getBehaviour(
308       const AnsysIntegerType id) const {
309     for (const auto &h : this->handlers) {
310       if (h.id == id) {
311         return h.f;
312       }
313     }
314     return nullptr;
315   }
316 
~UserMaterialManager()317   UserMaterialManager::~UserMaterialManager() {
318     for (auto &l : this->libraries) {
319 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
320       ::FreeLibrary(l.l);
321 #else  /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
322       ::dlclose(l.l);
323 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
324     }
325   }  // end of UserMaterialManager::~UserMaterialManager
326 
327 }  // end of namespace ansys
328 
329 extern "C" {
330 
331 #if (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__)
USERMAT(const int * const matId,const int * const elemId,const int * const kDomIntPt,const int * const kLayer,const int * const kSectPt,const int * const ldsetp,const int * const isubst,int * const keycut,const int * const nDirect,const int * const nShear,const int * const ncomp,const int * const nSatev,const int * const nProp,const double * const Time,const double * const dTime,const double * const Temp,const double * const dTemp,double * const stress,double * const statev,double * const dsdePl,double * const sedEl,double * const sedPl,double * const epseq,const double * const Strain,const double * const dStrain,double * const epsPl,const double * const prop,const double * const coords,const double * const rotateM,const double * const defGrad_t,const double * const defGrad,const double * const tsstif,double * const epsZZ,const double * const var1,const double * const var2,const double * const var3,const double * const var4,const double * const var5,const double * const var6,const double * const var7,const double * const var8)332 __declspec(dllexport) void USERMAT(const int *const matId,
333 #else  /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
334 void usermat_(const int *const matId,
335 #endif /* (defined _WIN32 || defined _WIN64) && (!defined __CYGWIN__) */
336                                    const int *const elemId,
337                                    const int *const kDomIntPt,
338                                    const int *const kLayer,
339                                    const int *const kSectPt,
340                                    const int *const ldsetp,
341                                    const int *const isubst,
342                                    int *const keycut,
343                                    const int *const nDirect,
344                                    const int *const nShear,
345                                    const int *const ncomp,
346                                    const int *const nSatev,
347                                    const int *const nProp,
348                                    const double *const Time,
349                                    const double *const dTime,
350                                    const double *const Temp,
351                                    const double *const dTemp,
352                                    double *const stress,
353                                    double *const statev,
354                                    double *const dsdePl,
355                                    double *const sedEl,
356                                    double *const sedPl,
357                                    double *const epseq,
358                                    const double *const Strain,
359                                    const double *const dStrain,
360                                    double *const epsPl,
361                                    const double *const prop,
362                                    const double *const coords,
363                                    const double *const rotateM,
364                                    const double *const defGrad_t,
365                                    const double *const defGrad,
366                                    const double *const tsstif,
367                                    double *const epsZZ,
368                                    const double *const var1,
369                                    const double *const var2,
370                                    const double *const var3,
371                                    const double *const var4,
372                                    const double *const var5,
373                                    const double *const var6,
374                                    const double *const var7,
375                                    const double *const var8) {
376   static ansys::UserMaterialManager m;
377   auto f = m.getBehaviour(*matId);
378   if (f == nullptr) {
379     usermat_exit("usermat: no behaviour associated to material id '" + std::to_string(*matId) +
380                  "'\n");
381   }
382   f(matId, elemId, kDomIntPt, kLayer, kSectPt, ldsetp, isubst, keycut, nDirect, nShear, ncomp,
383     nSatev, nProp, Time, dTime, Temp, dTemp, stress, statev, dsdePl, sedEl, sedPl, epseq, Strain,
384     dStrain, epsPl, prop, coords, rotateM, defGrad_t, defGrad, tsstif, epsZZ, var1, var2, var3,
385     var4, var5, var6, var7, var8);
386 }  // end of usermat
387 
388 }  // end of extern "C"
389