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