1 /*! 2 * \file mfront/src/CyranoInterface.cxx 3 * \brief 4 * \author Thomas Helfer 5 * \date 17 Jan 2007 6 * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights 7 * reserved. 8 * This project is publicly released under either the GNU GPL Licence 9 * or the CECILL-A licence. A copy of thoses licences are delivered 10 * with the sources of TFEL. CEA or EDF may also distribute this 11 * project under specific licensing conditions. 12 */ 13 14 #include <fstream> 15 #include <sstream> 16 #include <cstdlib> 17 #include <iterator> 18 #include <stdexcept> 19 #include <algorithm> 20 21 #include "TFEL/Raise.hxx" 22 #include "TFEL/Config/GetInstallPath.hxx" 23 #include "TFEL/Glossary/Glossary.hxx" 24 #include "TFEL/Glossary/GlossaryEntry.hxx" 25 #include "TFEL/Utilities/StringAlgorithms.hxx" 26 #include "TFEL/System/System.hxx" 27 28 #include "MFront/DSLUtilities.hxx" 29 #include "MFront/MFrontUtilities.hxx" 30 #include "MFront/MFrontLogStream.hxx" 31 #include "MFront/FileDescription.hxx" 32 #include "MFront/TargetsDescription.hxx" 33 #include "MFront/MaterialPropertyDescription.hxx" 34 #include "MFront/CyranoMaterialPropertyInterface.hxx" 35 #include "MFront/CyranoSymbolsGenerator.hxx" 36 #include "MFront/CyranoInterface.hxx" 37 38 #ifndef _MSC_VER 39 static const char* const constexpr_c = "constexpr"; 40 #else 41 static const char* const constexpr_c = "const"; 42 #endif 43 44 namespace mfront { 45 getName()46 std::string CyranoInterface::getName() { return "cyrano"; } 47 getModellingHypothesisIdentifier(const Hypothesis h)48 int CyranoInterface::getModellingHypothesisIdentifier(const Hypothesis h) { 49 switch (h) { 50 case ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN: 51 return 1; 52 case ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS: 53 return 2; 54 default: 55 break; 56 } 57 std::ostringstream msg; 58 msg << "CyranoInterface::getModellingHypothesisIdentifier : " 59 << "unsupported hypothesis"; 60 if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) { 61 msg << " (default)"; 62 } else { 63 msg << " (" << ModellingHypothesis::toString(h) << "')"; 64 } 65 tfel::raise(msg.str()); 66 } 67 getLibraryName(const BehaviourDescription & mb) const68 std::string CyranoInterface::getLibraryName(const BehaviourDescription& mb) const { 69 auto lib = std::string{}; 70 if (mb.getLibrary().empty()) { 71 if (!mb.getMaterialName().empty()) { 72 lib = "Cyrano" + mb.getMaterialName(); 73 } else { 74 lib = "CyranoBehaviour"; 75 } 76 } else { 77 lib = "Cyrano" + mb.getLibrary(); 78 } 79 return lib; 80 } // end of CyranoInterface::getLibraryName 81 getInterfaceName() const82 std::string CyranoInterface::getInterfaceName() const { 83 return "Cyrano"; 84 } // end of CyranoInterface::getInterfaceName 85 getFunctionNameBasis(const std::string & n) const86 std::string CyranoInterface::getFunctionNameBasis( 87 const std::string& n) const { 88 return "cyrano" + makeLowerCase(n); 89 } // end of CyranoInterface::getLibraryName 90 getBehaviourName(const std::string & library,const std::string & className) const91 std::string CyranoInterface::getBehaviourName(const std::string& library, 92 const std::string& className) const { 93 return library + className; 94 } // end of CyranoInterface::getBehaviourName 95 getUmatFunctionName(const std::string & library,const std::string & className) const96 std::string CyranoInterface::getUmatFunctionName(const std::string& library, 97 const std::string& className) const { 98 return "cyrano" + makeLowerCase(this->getBehaviourName(library, className)); 99 } // end of CyranoInterface::getUmatFunctionName 100 CyranoInterface()101 CyranoInterface::CyranoInterface() 102 : useTimeSubStepping(false), 103 doSubSteppingOnInvalidResults(false), 104 maximumSubStepping(0u) {} // end of CyranoInterface::CyranoInterface 105 treatKeyword(BehaviourDescription & bd,const std::string & key,const std::vector<std::string> & i,tokens_iterator current,const tokens_iterator end)106 std::pair<bool, CyranoInterface::tokens_iterator> CyranoInterface::treatKeyword( 107 BehaviourDescription& bd, 108 const std::string& key, 109 const std::vector<std::string>& i, 110 tokens_iterator current, 111 const tokens_iterator end) { 112 auto throw_if = [](const bool b, const std::string& m) { 113 tfel::raise_if(b, "Cyrano::treatKeyword: " + m); 114 }; 115 if (!i.empty()) { 116 if (std::find(i.begin(), i.end(), this->getName()) == i.end()) { 117 return {false, current}; 118 } 119 } 120 if ((key == "@CyranoGenerateMTestFileOnFailure") || 121 (key == "@UMATGenerateMTestFileOnFailure") || 122 (key == "@GenerateMTestFileOnFailure")) { 123 this->setGenerateMTestFileOnFailureAttribute( 124 bd, this->readBooleanValue(key, current, end)); 125 return {true, current}; 126 } else if ((key == "@CyranoUseTimeSubStepping") || (key == "@UMATUseTimeSubStepping")) { 127 this->useTimeSubStepping = this->readBooleanValue(key, current, end); 128 return {true, current}; 129 } else if ((key == "@CyranoMaximumSubStepping") || (key == "@UMATMaximumSubStepping")) { 130 throw_if(!this->useTimeSubStepping, 131 "time sub stepping is not enabled at this stage.\n" 132 "Use the @CyranoUseTimeSubStepping directive before " 133 "@CyranoMaximumSubStepping"); 134 throw_if(current == end, "unexpected end of file"); 135 std::istringstream flux(current->value); 136 flux >> this->maximumSubStepping; 137 throw_if(flux.fail(), "failed to read maximum substepping value."); 138 ++(current); 139 throw_if(current == end, "unexpected end of file"); 140 throw_if(current->value != ";", "expected ';',read '" + current->value + "'"); 141 ++(current); 142 return {true, current}; 143 } else if ((key == "@CyranoDoSubSteppingOnInvalidResults") || 144 (key == "@UMATDoSubSteppingOnInvalidResults")) { 145 throw_if(!this->useTimeSubStepping, 146 "time sub stepping is not " 147 "enabled at this stage.\n" 148 "Use the @CyranoUseTimeSubStepping directive before " 149 "@CyranoMaximumSubStepping"); 150 this->doSubSteppingOnInvalidResults = this->readBooleanValue(key, current, end); 151 return {true, current}; 152 } 153 return {false, current}; 154 } // end of treatKeyword 155 getModellingHypothesesToBeTreated(const BehaviourDescription & mb) const156 std::set<CyranoInterface::Hypothesis> CyranoInterface::getModellingHypothesesToBeTreated( 157 const BehaviourDescription& mb) const { 158 // treatment 159 std::set<Hypothesis> h; 160 // modelling hypotheses handled by the behaviour 161 const auto& bh = mb.getModellingHypotheses(); 162 // cyrano only supports the AxisymmetricalGeneralisedPlaneStrain 163 // and the AxisymmetricalGeneralisedPlaneStress hypotheses 164 if (bh.find(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN) != bh.end()) { 165 h.insert(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN); 166 } 167 if (bh.find(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) != bh.end()) { 168 h.insert(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS); 169 } 170 tfel::raise_if(h.empty(), 171 "CyranoInterface::getModellingHypothesesToBeTreated : " 172 "no hypotheses selected. This means that the given beahviour " 173 "can't be used neither in 'AxisymmetricalGeneralisedPlaneStrain' " 174 "nor in 'AxisymmetricalGeneralisedPlaneStress', so it does not " 175 "make sense to use the Cyrano interface"); 176 return h; 177 } // end of CyranoInterface::getModellingHypothesesToBeTreated 178 writeGetOutOfBoundsPolicyFunctionImplementation(std::ostream & out,const std::string & name) const179 void CyranoInterface::writeGetOutOfBoundsPolicyFunctionImplementation( 180 std::ostream& out, const std::string& name) const { 181 out << "static tfel::material::OutOfBoundsPolicy&\n" 182 << this->getFunctionNameBasis(name) << "_getOutOfBoundsPolicy(){\n" 183 << "using namespace cyrano;\n" 184 << "using namespace tfel::material;\n" 185 << "static OutOfBoundsPolicy policy = " 186 "CyranoOutOfBoundsPolicy::getCyranoOutOfBoundsPolicy()." 187 "getOutOfBoundsPolicy();\n" 188 << "return policy;\n" 189 << "}\n\n"; 190 } // end of MFrontCyranoInterface::writeGetOutOfBoundsPolicyFunctionImplementation 191 endTreatment(const BehaviourDescription & mb,const FileDescription & fd) const192 void CyranoInterface::endTreatment(const BehaviourDescription& mb, 193 const FileDescription& fd) const { 194 using namespace std; 195 using namespace tfel::system; 196 using namespace tfel::utilities; 197 auto throw_if = [](const bool b, const std::string& m) { 198 tfel::raise_if(b, "Cyrano::endTreatment: " + m); 199 }; 200 // get the modelling hypotheses to be treated 201 const auto& mhs = this->getModellingHypothesesToBeTreated(mb); 202 const auto name = mb.getLibrary() + mb.getClassName(); 203 // some checks 204 throw_if(mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR, 205 "the cyrano interface only supports " 206 "small strain behaviours"); 207 if (mb.isStrainMeasureDefined()) { 208 throw_if((mb.getStrainMeasure() != BehaviourDescription::LINEARISED) && 209 (mb.getStrainMeasure() != BehaviourDescription::HENCKY), 210 "the cyrano interface only supports:\n" 211 "- small strain behaviours: the only strain measure " 212 "supported is the HPP one (linearised)\n" 213 "- finite strain behaviours based on the Hencky strain measure"); 214 } 215 if (mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) { 216 throw_if(mb.getSymmetryType() != mb.getElasticSymmetryType(), 217 "the type of the behaviour (isotropic or orthotropic) does not " 218 "match the the type of its elastic behaviour.\n" 219 "This is not allowed here :\n" 220 "- an isotropic behaviour must have an isotropic elastic behaviour\n" 221 "- an orthotropic behaviour must have an orthotropic elastic behaviour"); 222 } 223 if (this->useTimeSubStepping) { 224 throw_if(this->maximumSubStepping == 0u, 225 "use of time sub stepping requested but MaximumSubStepping is zero.\n" 226 "Please use the @CyranoMaximumSubStepping directive"); 227 } 228 // create the output directories 229 systemCall::mkdir("include/MFront"); 230 systemCall::mkdir("include/MFront/Cyrano"); 231 232 // write the material properties 233 if (mb.areElasticMaterialPropertiesDefined()) { 234 for (const auto& emp : mb.getElasticMaterialPropertiesDescriptions()) { 235 CyranoMaterialPropertyInterface i; 236 i.writeOutputFiles(emp, fd); 237 } 238 } 239 240 // opening header file 241 auto fileName = "cyrano"+name+".hxx"; 242 std::ofstream out("include/MFront/Cyrano/" + fileName); 243 throw_if(!out, "could not open file '" + fileName + "'"); 244 245 out << "/*!\n"; 246 out << "* \\file " << fileName << endl; 247 out << "* \\brief This file declares the cyrano interface for the " << mb.getClassName() 248 << " behaviour law\n"; 249 out << "* \\author " << fd.authorName << endl; 250 out << "* \\date " << fd.date << endl; 251 out << "*/\n\n"; 252 253 const auto header = this->getHeaderGuard(mb); 254 out << "#ifndef " << header << "\n"; 255 out << "#define " << header << "\n\n"; 256 257 out << "#include\"TFEL/Config/TFELConfig.hxx\"\n\n"; 258 out << "#include\"MFront/Cyrano/Cyrano.hxx\"\n\n"; 259 260 out << "#ifdef __cplusplus\n"; 261 out << "#include\"MFront/Cyrano/CyranoTraits.hxx\"\n"; 262 out << "#include\"TFEL/Material/" << mb.getClassName() << ".hxx\"\n"; 263 out << "#endif /* __cplusplus */\n\n"; 264 265 this->writeVisibilityDefines(out); 266 267 out << "#ifdef __cplusplus\n\n"; 268 269 out << "namespace cyrano{\n\n"; 270 271 if (!mb.areAllMechanicalDataSpecialised(mhs)) { 272 this->writeCyranoBehaviourTraits(out, mb, ModellingHypothesis::UNDEFINEDHYPOTHESIS); 273 } 274 for (const auto& h : mhs) { 275 if (mb.hasSpecialisedMechanicalData(h)) { 276 this->writeCyranoBehaviourTraits(out, mb, h); 277 } 278 } 279 280 out << "} // end of namespace cyrano\n\n"; 281 282 out << "#endif /* __cplusplus */\n\n"; 283 284 out << "#ifdef __cplusplus\n"; 285 out << "extern \"C\"{\n"; 286 out << "#endif /* __cplusplus */\n\n"; 287 288 this->writeSetParametersFunctionsDeclarations(out, mb, name); 289 this->writeSetOutOfBoundsPolicyFunctionDeclaration(out, name); 290 291 this->writeCyranoFunctionDeclaration(out, name); 292 293 out << "#ifdef __cplusplus\n"; 294 out << "}\n"; 295 out << "#endif /* __cplusplus */\n\n"; 296 297 out << "#endif /* " << header << " */\n"; 298 299 out.close(); 300 301 fileName = "cyrano"+name+".cxx"; 302 out.open("src/" + fileName); 303 tfel::raise_if(!out, 304 "CyranoInterface::endTreatment: " 305 "could not open file '" + 306 fileName + "'"); 307 308 out << "/*!\n"; 309 out << "* \\file " << fileName << endl; 310 out << "* \\brief This file implements the cyrano interface for the " << mb.getClassName() 311 << " behaviour law\n"; 312 out << "* \\author " << fd.authorName << endl; 313 out << "* \\date " << fd.date << endl; 314 out << "*/\n\n"; 315 316 this->getExtraSrcIncludes(out, mb); 317 if (mb.getAttribute(BehaviourData::profiling, false)) { 318 out << "#include\"MFront/BehaviourProfiler.hxx\"\n\n"; 319 } 320 if (this->shallGenerateMTestFileOnFailure(mb)) { 321 out << "#include\"MFront/Cyrano/CyranoGetModellingHypothesis.hxx\"\n"; 322 } 323 out << "#include\"MFront/Cyrano/CyranoInterface.hxx\"\n\n"; 324 out << "#include\"TFEL/Material/" << mb.getClassName() << ".hxx\"\n"; 325 out << "#include\"MFront/Cyrano/CyranoOutOfBoundsPolicy.hxx\"\n"; 326 out << "#include\"MFront/Cyrano/CyranoStressFreeExpansionHandler.hxx\"\n"; 327 out << "#include\"MFront/Cyrano/cyrano" << name << ".hxx\"\n\n"; 328 329 this->writeGetOutOfBoundsPolicyFunctionImplementation(out, name); 330 331 out << "extern \"C\"{\n\n"; 332 333 CyranoSymbolsGenerator sg; 334 sg.generateGeneralSymbols(out, *this, mb, fd, mhs, name); 335 if (!mb.areAllMechanicalDataSpecialised(mhs)) { 336 const Hypothesis uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS; 337 sg.generateSymbols(out, *this, mb, fd, name, uh); 338 } 339 for (const auto& h : mhs) { 340 if (mb.hasSpecialisedMechanicalData(h)) { 341 sg.generateSymbols(out, *this, mb, fd, name, h); 342 } 343 } 344 345 out << "MFRONT_SHAREDOBJ unsigned short cyrano" << makeLowerCase(name) 346 << "_Interface = 1u;\n\n"; 347 348 this->writeSetParametersFunctionsImplementations(out, mb, name); 349 this->writeSetOutOfBoundsPolicyFunctionImplementation(out, name); 350 351 if (mb.isStrainMeasureDefined()) { 352 if (mb.getStrainMeasure() == BehaviourDescription::HENCKY) { 353 this->writeLogarithmicStrainCyranoFunction(out, name, mb); 354 } else { 355 this->writeStandardCyranoFunction(out, name, mb); 356 } 357 } else { 358 this->writeStandardCyranoFunction(out, name, mb); 359 } 360 out << "} // end of extern \"C\"\n"; 361 out.close(); 362 } // end of CyranoInterface::endTreatment 363 writeMTestFileGeneratorSetModellingHypothesis(std::ostream & out) const364 void CyranoInterface::writeMTestFileGeneratorSetModellingHypothesis(std::ostream& out) const { 365 out << "mg.setModellingHypothesis(cyrano::getModellingHypothesis(*NDI));\n"; 366 } 367 368 CyranoInterface::~CyranoInterface() = default; 369 getTargetsDescription(TargetsDescription & d,const BehaviourDescription & bd)370 void CyranoInterface::getTargetsDescription(TargetsDescription& d, 371 const BehaviourDescription& bd) { 372 const auto lib = CyranoInterface::getLibraryName(bd); 373 const auto name = ((!bd.getLibrary().empty()) ? bd.getLibrary() : "") + bd.getClassName(); 374 const auto tfel_config = tfel::getTFELConfigExecutableName(); 375 auto& l = d.getLibrary(lib); 376 insert_if(l.cppflags, 377 "$(shell " + tfel_config + " --cppflags --compiler-flags)"); 378 #if CYRANO_ARCH == 64 379 insert_if(l.cppflags, "-DCYRANO_ARCH=64"); 380 #elif CYRANO_ARCH == 32 381 insert_if(l.cppflags, "-DCYRANO_ARCH=32"); 382 #else 383 #error "CyranoInterface::getGlobalIncludes : unsuported architecture" 384 #endif 385 insert_if(l.include_directories, 386 "$(shell " + tfel_config + " --include-path)"); 387 insert_if(l.sources, "cyrano" + name + ".cxx"); 388 insert_if(l.epts, name); 389 insert_if(l.epts, this->getFunctionNameBasis(name)); 390 insert_if(d.headers, "MFront/Cyrano/cyrano" + name + ".hxx"); 391 insert_if(l.link_directories, 392 "$(shell " + tfel_config + " --library-path)"); 393 insert_if(l.link_libraries, tfel::getLibraryInstallName("CyranoInterface")); 394 if (this->shallGenerateMTestFileOnFailure(bd)) { 395 insert_if(l.link_libraries, 396 tfel::getLibraryInstallName("MTestFileGenerator")); 397 } 398 #if __cplusplus >= 201703L 399 insert_if(l.link_libraries, "$(shell " + tfel_config + 400 " --library-dependency " 401 "--material --mfront-profiling)"); 402 #else /* __cplusplus < 201703L */ 403 insert_if(l.link_libraries, 404 "$(shell " + tfel_config + 405 " --library-dependency " 406 "--material --mfront-profiling --physical-constants)"); 407 #endif /* __cplusplus < 201703L */ 408 if (bd.areElasticMaterialPropertiesDefined()) { 409 for (const auto& emp : bd.getElasticMaterialPropertiesDescriptions()) { 410 CyranoMaterialPropertyInterface i; 411 i.getLibraryDescription(d, l, emp); 412 } 413 } 414 } // end of CyranoInterface::getTargetsDescription(TargetsDescription&) 415 writeInterfaceSpecificIncludes(std::ostream & out,const BehaviourDescription &) const416 void CyranoInterface::writeInterfaceSpecificIncludes(std::ostream& out, 417 const BehaviourDescription&) const { 418 out << "#include\"MFront/Cyrano/Cyrano.hxx\"\n\n"; 419 } 420 writeCyranoFunctionDeclaration(std::ostream & out,const std::string & name) const421 void CyranoInterface::writeCyranoFunctionDeclaration(std::ostream& out, 422 const std::string& name) const { 423 using namespace std; 424 out << "MFRONT_SHAREDOBJ void\n" 425 << name << "(const cyrano::CyranoInt *const,const cyrano::CyranoReal *const,\n" 426 << "const cyrano::CyranoReal *const, cyrano::CyranoReal *const,\n" 427 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 428 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 429 << "const cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 430 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 431 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 432 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 433 << " cyrano::CyranoInt *const);\n\n"; 434 out << "MFRONT_SHAREDOBJ void\n" 435 << makeUpperCase(name) << "_F77" 436 << "(const cyrano::CyranoInt *const,const cyrano::CyranoReal *const,\n" 437 << "const cyrano::CyranoReal *const, cyrano::CyranoReal *const,\n" 438 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 439 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 440 << "const cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 441 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 442 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 443 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 444 << " cyrano::CyranoInt *const);\n\n"; 445 out << "MFRONT_SHAREDOBJ void\ncyrano" << makeLowerCase(name) 446 << "(const cyrano::CyranoInt *const,const cyrano::CyranoReal *const,\n" 447 << "const cyrano::CyranoReal *const, cyrano::CyranoReal *const,\n" 448 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 449 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 450 << "const cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 451 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 452 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 453 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 454 << " cyrano::CyranoInt *const);\n\n"; 455 out << "MFRONT_SHAREDOBJ void\n" 456 << "cyrano" << makeUpperCase(name) << "_F77" 457 << "(const cyrano::CyranoInt *const,const cyrano::CyranoReal *const,\n" 458 << "const cyrano::CyranoReal *const, cyrano::CyranoReal *const,\n" 459 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 460 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 461 << "const cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 462 << "const cyrano::CyranoReal *const,const cyrano::CyranoReal *const,\n" 463 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 464 << " cyrano::CyranoReal *const,const cyrano::CyranoInt *const,\n" 465 << " cyrano::CyranoInt *const);\n\n"; 466 } // end of CyranoInterface::writeCyranoFunctionDeclaration 467 writeSecondaryCyranoFunction(std::ostream & out,const std::string & fname,const std::string & n)468 static void writeSecondaryCyranoFunction(std::ostream& out, 469 const std::string& fname, 470 const std::string& n) { 471 out << "MFRONT_SHAREDOBJ void\n" 472 << fname 473 << "(const cyrano::CyranoInt *const NTENS, const cyrano::CyranoReal *const DTIME,\n" 474 << "const cyrano::CyranoReal *const DROT, cyrano::CyranoReal *const DDSDDE,\n" 475 << "const cyrano::CyranoReal *const STRAN, const cyrano::CyranoReal *const DSTRAN,\n" 476 << "const cyrano::CyranoReal *const TEMP, const cyrano::CyranoReal *const DTEMP,\n" 477 << "const cyrano::CyranoReal *const PROPS, const cyrano::CyranoInt *const NPROPS,\n" 478 << "const cyrano::CyranoReal *const PREDEF,const cyrano::CyranoReal *const DPRED,\n" 479 << "cyrano::CyranoReal *const STATEV,const cyrano::CyranoInt *const NSTATV,\n" 480 << "cyrano::CyranoReal *const STRESS,const cyrano::CyranoInt *const NDI,\n" 481 << "cyrano::CyranoInt *const KINC)\n" 482 << "{\n" 483 << n << "(NTENS, DTIME,DROT,DDSDDE,STRAN,DSTRAN,TEMP,DTEMP,\n" 484 << "PROPS,NPROPS,PREDEF,DPRED,STATEV,NSTATV,\n" 485 << "STRESS,NDI,KINC);\n"; 486 out << "}\n\n"; 487 } // end of writeSecondaryCyranoFunction 488 writeStandardCyranoFunction(std::ostream & out,const std::string & n,const BehaviourDescription & mb) const489 void CyranoInterface::writeStandardCyranoFunction(std::ostream& out, 490 const std::string& n, 491 const BehaviourDescription& mb) const { 492 out << "MFRONT_SHAREDOBJ void\n" 493 << n << "(const cyrano::CyranoInt *const NTENS, const cyrano::CyranoReal *const DTIME,\n" 494 << "const cyrano::CyranoReal *const DROT, cyrano::CyranoReal *const DDSDDE,\n" 495 << "const cyrano::CyranoReal *const STRAN, const cyrano::CyranoReal *const DSTRAN,\n" 496 << "const cyrano::CyranoReal *const TEMP, const cyrano::CyranoReal *const DTEMP,\n" 497 << "const cyrano::CyranoReal *const PROPS, const cyrano::CyranoInt *const NPROPS,\n" 498 << "const cyrano::CyranoReal *const PREDEF,const cyrano::CyranoReal *const DPRED,\n" 499 << "cyrano::CyranoReal *const STATEV,const cyrano::CyranoInt *const NSTATV,\n" 500 << "cyrano::CyranoReal *const STRESS,const cyrano::CyranoInt *const NDI,\n" 501 << "cyrano::CyranoInt *const KINC)\n"; 502 out << "{\n"; 503 out << "const auto op = " << this->getFunctionNameBasis(n) 504 << "_getOutOfBoundsPolicy();\n"; 505 if (mb.getAttribute(BehaviourData::profiling, false)) { 506 out << "using mfront::BehaviourProfiler;\n"; 507 out << "using tfel::material::" << mb.getClassName() << "Profiler;\n"; 508 out << "auto total_timer(" << mb.getClassName() << "Profiler::getProfiler(),\n" 509 << "BehaviourProfiler::TOTALTIME);\n"; 510 } 511 this->generateMTestFile1(out, mb); 512 out << "cyrano::CyranoInterface<tfel::material::" << mb.getClassName() 513 << ">::exe(NTENS,DTIME,DROT,DDSDDE,STRAN,DSTRAN,TEMP,DTEMP,PROPS,NPROPS," 514 << "PREDEF,DPRED,STATEV,NSTATV,STRESS,NDI,KINC," 515 << "cyrano::CyranoStandardSmallStrainStressFreeExpansionHandler,op);\n"; 516 if (this->shallGenerateMTestFileOnFailure(mb)) { 517 out << "if(*KINC<0){\n"; 518 this->generateMTestFile2(out, mb, BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR, n, ""); 519 out << "}\n"; 520 } 521 out << "}\n\n"; 522 writeSecondaryCyranoFunction(out, this->getFunctionNameBasis(n), n); 523 } // end of CyranoInterface::writeStandardCyranoFunction 524 writeLogarithmicStrainCyranoFunction(std::ostream & out,const std::string & n,const BehaviourDescription & mb) const525 void CyranoInterface::writeLogarithmicStrainCyranoFunction(std::ostream& out, 526 const std::string& n, 527 const BehaviourDescription& mb) const { 528 auto throw_if = [](const bool b, const std::string& m) { 529 if (b) { 530 tfel::raise("CyranoInterface::writeLogarithmicStrainCyranoFunction: " + m); 531 } 532 }; 533 out << "MFRONT_SHAREDOBJ void\n" 534 << n << "(const cyrano::CyranoInt *const NTENS, const cyrano::CyranoReal *const DTIME,\n" 535 << "const cyrano::CyranoReal *const DROT, cyrano::CyranoReal *const DDSDDE,\n" 536 << "const cyrano::CyranoReal *const STRAN, const cyrano::CyranoReal *const DSTRAN,\n" 537 << "const cyrano::CyranoReal *const TEMP, const cyrano::CyranoReal *const DTEMP,\n" 538 << "const cyrano::CyranoReal *const PROPS, const cyrano::CyranoInt *const NPROPS,\n" 539 << "const cyrano::CyranoReal *const PREDEF,const cyrano::CyranoReal *const DPRED,\n" 540 << "cyrano::CyranoReal *const STATEV,const cyrano::CyranoInt *const NSTATV,\n" 541 << "cyrano::CyranoReal *const STRESS,const cyrano::CyranoInt *const NDI,\n" 542 << "cyrano::CyranoInt *const KINC)\n" 543 << "{\n"; 544 out << "const auto op = " << this->getFunctionNameBasis(n) 545 << "_getOutOfBoundsPolicy();\n"; 546 if (mb.getAttribute(BehaviourData::profiling, false)) { 547 out << "using mfront::BehaviourProfiler;\n" 548 << "using tfel::material::" << mb.getClassName() << "Profiler;\n" 549 << "auto total_timer(" << mb.getClassName() << "Profiler::getProfiler(),\n" 550 << "BehaviourProfiler::TOTALTIME);\n"; 551 } 552 this->generateMTestFile1(out, mb); 553 out << "const auto k = std::abs(*DDSDDE)>0.5;\n" 554 << "// computing the logarithmic strain\n" 555 << "cyrano::CyranoReal eto[3];\n" 556 << "cyrano::CyranoReal deto[3];\n" 557 << "cyrano::CyranoReal s[3];\n" 558 << "cyrano::CyranoReal K[9];\n"; 559 // axisymmetrical generalised plane stress 560 out << "if(*NDI!=1){\n" 561 << "// axisymmetrical generalised plane stress\n"; 562 if (mb.isModellingHypothesisSupported( 563 ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS)) { 564 const auto& d = 565 mb.getBehaviourData(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS); 566 // this must be added for gcc 4.7.2 567 const auto astress = [this,&d, throw_if]() -> std::pair<bool, SupportedTypes::TypeSize> { 568 SupportedTypes::TypeSize o; 569 // skipping the temperature 570 auto pev = std::next(d.getExternalStateVariables().begin()); 571 while (pev != d.getExternalStateVariables().end()) { 572 if (d.getExternalName(pev->name) == tfel::glossary::Glossary::AxialStress) { 573 throw_if( 574 SupportedTypes::getTypeFlag(pev->type) != 575 SupportedTypes::SCALAR, 576 "invalid type for the `AxialStress` external state variable"); 577 return {true, o}; 578 } 579 o += SupportedTypes::getTypeSize(pev->type, pev->arraySize); 580 ++pev; 581 } 582 return {false, o}; 583 }(); 584 const auto astrain = this->checkIfAxialStrainIsDefinedAndGetItsOffset( 585 mb, ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS); 586 tfel::raise_if(!astress.first, "no external state state variable standing for the axial stress"); 587 tfel::raise_if(!astrain.first, "no state variable standing for the axial strain"); 588 if (mb.getAttribute(BehaviourData::profiling, false)) { 589 out << "{\n" 590 << "auto pre_timer(" << mb.getClassName() << "Profiler::getProfiler(),\n" 591 << "BehaviourProfiler::FINITESTRAINPREPROCESSING);\n"; 592 } 593 out << "const auto Pzz0 = PREDEF[" << astress.second.getValueForDimension(1) << "];\n" 594 << "const auto Pzz1 = Pzz0+DPRED[" << astress.second.getValueForDimension(1) << "];\n" 595 << "const auto Tzz0 = " 596 << "Pzz0*std::exp(STATEV[" << astrain.second.getValueForDimension(1) << "]);\n" 597 << "eto[0]=std::log1p(*STRAN);\n" 598 << "eto[1]=std::log1p(*(STRAN+1));\n" 599 << "eto[2]=0;\n" 600 << "deto[0]=std::log1p(*STRAN+*DSTRAN)-eto[0];\n" 601 << "deto[1]=std::log1p(*(STRAN+1)+*(DSTRAN+1))-eto[1];\n" 602 << "deto[2]=0;\n" 603 << "s[0]=(*STRESS)*(1+*STRAN);\n" 604 << "s[1]=(*(STRESS+1))*(1+*(STRAN+1));\n" 605 << "s[2]=Tzz0;\n" 606 << "K[0]=*DDSDDE;\n"; 607 if (mb.getAttribute(BehaviourData::profiling, false)) { 608 out << "}\n"; 609 } 610 out << "cyrano::CyranoInterface<tfel::material::" << mb.getClassName() 611 << ">::exe(NTENS,DTIME,DROT,K,eto,deto,TEMP,DTEMP,PROPS,NPROPS," 612 << "PREDEF,DPRED,STATEV,NSTATV,s,NDI,KINC," 613 << "cyrano::CyranoLogarithmicStrainStressFreeExpansionHandler,op);\n"; 614 out << "if(*KINC>=0){\n"; 615 if (mb.getAttribute(BehaviourData::profiling, false)) { 616 out << "{\n" 617 << "auto post_timer(" << mb.getClassName() << "Profiler::getProfiler(),\n" 618 << "BehaviourProfiler::FINITESTRAINPOSTPROCESSING);\n"; 619 } 620 // First Piola-Kirchhoff stress 621 out << "STRESS[0]=s[0]/(1+*STRAN+*DSTRAN);\n" 622 << "STRESS[1]=s[1]/(1+*(STRAN+1)+*(DSTRAN+1));\n" 623 << "STRESS[2]=Pzz1;\n"; 624 // computation of the stiffness matrix 625 out << "if(k){\n" 626 << "*DDSDDE = (-STRESS[0]+K[0]/(1+STRAN[0]+DSTRAN[0]))/(1+STRAN[0]+DSTRAN[0]);\n" 627 << "*(DDSDDE+3) = K[3]/((1+STRAN[1]+DSTRAN[1])*(1+STRAN[0]+DSTRAN[0]));\n" 628 << "*(DDSDDE+6) = 0;\n" 629 << "*(DDSDDE+1) = K[1]/((1+STRAN[0]+DSTRAN[0])*(1+STRAN[1]+DSTRAN[1]));\n" 630 << "*(DDSDDE+4) = (-STRESS[1]+K[4]/(1+STRAN[1]+DSTRAN[1]))/(1+STRAN[1]+DSTRAN[1]);\n" 631 << "*(DDSDDE+7) = 0;\n" 632 << "*(DDSDDE+2) = 0;\n" 633 << "*(DDSDDE+5) = 0;\n" 634 << "*(DDSDDE+8) = 0;\n" 635 << "}\n"; 636 if (mb.getAttribute(BehaviourData::profiling, false)) { 637 out << "}\n"; 638 } 639 out << "}\n"; 640 } else { 641 out << "*KINC=-7;\n" 642 << "return;\n"; 643 } 644 // axisymmetrical generalised plane strain 645 out << "} else {\n" 646 << "// axisymmetrical generalised plane strain\n"; 647 if (mb.getAttribute(BehaviourData::profiling, false)) { 648 out << "{\n" 649 << "auto pre_timer(" << mb.getClassName() << "Profiler::getProfiler(),\n" 650 << "BehaviourProfiler::FINITESTRAINPREPROCESSING);\n"; 651 } 652 out << "eto[0]=std::log1p(*STRAN);\n" 653 << "eto[1]=std::log1p(*(STRAN+1));\n" 654 << "eto[2]=std::log1p(*(STRAN+2));\n" 655 << "deto[0]=std::log1p(*STRAN+*DSTRAN)-eto[0];\n" 656 << "deto[1]=std::log1p(*(STRAN+1)+*(DSTRAN+1))-eto[1];\n" 657 << "deto[2]=std::log1p(*(STRAN+2)+*(DSTRAN+2))-eto[2];\n" 658 << "s[0]=(*STRESS)*(1+*STRAN);\n" 659 << "s[1]=(*(STRESS+1))*(1+*(STRAN+1));\n" 660 << "s[2]=(*(STRESS+2))*(1+*(STRAN+2));\n"; 661 if (mb.getAttribute(BehaviourData::profiling, false)) { 662 out << "}\n"; 663 } 664 out << "K[0]=*DDSDDE;\n" 665 << "cyrano::CyranoInterface<tfel::material::" << mb.getClassName() 666 << ">::exe(NTENS,DTIME,DROT,K,eto,deto,TEMP,DTEMP,PROPS,NPROPS," 667 << "PREDEF,DPRED,STATEV,NSTATV,s,NDI,KINC," 668 << "cyrano::CyranoLogarithmicStrainStressFreeExpansionHandler,op);\n"; 669 out << "if(*KINC>=0){\n"; 670 if (mb.getAttribute(BehaviourData::profiling, false)) { 671 out << "{\n" 672 << "auto post_timer(" << mb.getClassName() << "Profiler::getProfiler(),\n" 673 << "BehaviourProfiler::FINITESTRAINPOSTPROCESSING);\n"; 674 } 675 // First Piola-Kirchhoff stress 676 out << "STRESS[0]=s[0]/(1+*STRAN+*DSTRAN);\n" 677 << "STRESS[1]=s[1]/(1+*(STRAN+1)+*(DSTRAN+1));\n" 678 << "STRESS[2]=s[2]/(1+*(STRAN+2)+*(DSTRAN+2));\n"; 679 // computation of the stiffness matrix 680 out << "if(k){\n" 681 << "*DDSDDE = (-STRESS[0]+K[0]/(1+STRAN[0]+DSTRAN[0]))/(1+STRAN[0]+DSTRAN[0]);\n" 682 << "*(DDSDDE+3) = K[3]/((1+STRAN[1]+DSTRAN[1])*(1+STRAN[0]+DSTRAN[0]));\n" 683 << "*(DDSDDE+6) = K[6]/((1+STRAN[2]+DSTRAN[2])*(1+STRAN[0]+DSTRAN[0]));\n" 684 << "*(DDSDDE+1) = K[1]/((1+STRAN[0]+DSTRAN[0])*(1+STRAN[1]+DSTRAN[1]));\n" 685 << "*(DDSDDE+4) = (-STRESS[1]+K[4]/(1+STRAN[1]+DSTRAN[1]))/(1+STRAN[1]+DSTRAN[1]);\n" 686 << "*(DDSDDE+7) = K[7]/((1+STRAN[2]+DSTRAN[2])*(1+STRAN[1]+DSTRAN[1]));\n" 687 << "*(DDSDDE+2) = K[2]/((1+STRAN[0]+DSTRAN[0])*(1+STRAN[2]+DSTRAN[2]));\n" 688 << "*(DDSDDE+5) = K[5]/((1+STRAN[1]+DSTRAN[1])*(1+STRAN[2]+DSTRAN[2]));\n" 689 << "*(DDSDDE+8) = (-STRESS[2]+K[8]/(1+STRAN[2]+DSTRAN[2]))/(1+STRAN[2]+DSTRAN[2]);\n" 690 << "}\n"; 691 if (mb.getAttribute(BehaviourData::profiling, false)) { 692 out << "}\n"; 693 } 694 out << "} // end of if(*KINC>=0)\n"; 695 out << "} // end of if(*NDI!=1)\n"; 696 if (this->shallGenerateMTestFileOnFailure(mb)) { 697 out << "if(*KINC<0){\n"; 698 this->generateMTestFile2(out, mb,BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR, n, ""); 699 out << "}\n"; 700 } 701 out << "}\n\n"; 702 writeSecondaryCyranoFunction(out, this->getFunctionNameBasis(n), n); 703 } // end of CyranoInterface::writeLogarithmicStrainCyranoFunction 704 writeCyranoBehaviourTraits(std::ostream & out,const BehaviourDescription & mb,const Hypothesis h) const705 void CyranoInterface::writeCyranoBehaviourTraits(std::ostream& out, 706 const BehaviourDescription& mb, 707 const Hypothesis h) const { 708 using namespace tfel::material; 709 const auto mvs = mb.getMainVariablesSize(); 710 const auto mprops = this->buildMaterialPropertiesList(mb, h); 711 if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) { 712 out << "template<tfel::material::ModellingHypothesis::Hypothesis H,typename Type"; 713 if (mb.useQt()) { 714 out << ",bool use_qt"; 715 } 716 } else { 717 out << "template<typename Type"; 718 if (mb.useQt()) { 719 out << ",bool use_qt"; 720 } 721 } 722 out << ">\n"; 723 if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) { 724 out << "struct CyranoTraits<tfel::material::" << mb.getClassName() << "<H,Type,"; 725 } else { 726 out << "struct CyranoTraits<tfel::material::" << mb.getClassName() 727 << "<tfel::material::ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) 728 << ",Type,"; 729 } 730 if (mb.useQt()) { 731 out << "use_qt"; 732 } else { 733 out << "false"; 734 } 735 out << "> >{\n"; 736 if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) { 737 out << "// modelling hypothesis\n"; 738 out << "static " << constexpr_c << " tfel::material::ModellingHypothesis::Hypothesis H = " 739 << "tfel::material::ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) 740 << ";\n"; 741 } 742 out << "// space dimension\n"; 743 out << "static " << constexpr_c << " unsigned short N = " 744 "tfel::material::ModellingHypothesisToSpaceDimension<H>::" 745 "value;\n"; 746 out << "// tiny vector size\n"; 747 out << "static " << constexpr_c << " unsigned short TVectorSize = N;\n"; 748 out << "// symmetric tensor size\n"; 749 out << "static " << constexpr_c 750 << " unsigned short StensorSize = tfel::math::StensorDimeToSize<N>::value;\n"; 751 out << "// tensor size\n"; 752 out << "static " << constexpr_c 753 << " unsigned short TensorSize = tfel::math::TensorDimeToSize<N>::value;\n"; 754 out << "// size of the driving variable array (STRAN)\n"; 755 out << "static " << constexpr_c << " unsigned short GradientSize = " << mvs.first 756 << ";\n"; 757 out << "// size of the thermodynamic force variable array (STRAN)\n"; 758 out << "static " << constexpr_c 759 << " unsigned short ThermodynamicForceVariableSize = " << mvs.second << ";\n"; 760 out << "static " << constexpr_c << " bool useTimeSubStepping = "; 761 if (this->useTimeSubStepping) { 762 out << "true;\n"; 763 } else { 764 out << "false;\n"; 765 } 766 out << "static " << constexpr_c << " bool doSubSteppingOnInvalidResults = "; 767 if (this->doSubSteppingOnInvalidResults) { 768 out << "true;\n"; 769 } else { 770 out << "false;\n"; 771 } 772 out << "static " << constexpr_c << " unsigned short maximumSubStepping = "; 773 if (this->useTimeSubStepping) { 774 out << this->maximumSubStepping << ";\n"; 775 } else { 776 out << "0u;\n"; 777 } 778 if (mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) { 779 out << "static " << constexpr_c << " bool requiresStiffnessTensor = true;\n"; 780 if (mb.getAttribute(BehaviourDescription::requiresUnAlteredStiffnessTensor, false)) { 781 out << "static " << constexpr_c << " bool requiresUnAlteredStiffnessTensor = true;\n"; 782 } else { 783 out << "static " << constexpr_c << " bool requiresUnAlteredStiffnessTensor = false;\n"; 784 } 785 } else { 786 out << "static " << constexpr_c << " bool requiresStiffnessTensor = false;\n"; 787 } 788 if (mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, false)) { 789 out << "static " << constexpr_c 790 << " bool requiresThermalExpansionCoefficientTensor = true;\n"; 791 } else { 792 out << "static " << constexpr_c 793 << " bool requiresThermalExpansionCoefficientTensor = false;\n"; 794 } 795 // computing material properties size 796 SupportedTypes::TypeSize msize; 797 if (!mprops.first.empty()) { 798 const auto& m = mprops.first.back(); 799 msize = m.offset; 800 msize += SupportedTypes::getTypeSize(m.type, m.arraySize); 801 msize -= mprops.second; 802 } 803 out << "static " << constexpr_c << " unsigned short material_properties_nb = " << msize 804 << ";\n"; 805 if (mb.getSymmetryType() == mfront::ISOTROPIC) { 806 if (mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) { 807 if (mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, 808 false)) { 809 out << "static " << constexpr_c << " unsigned short propertiesOffset = 3u;\n"; 810 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 2u;\n"; 811 } else { 812 out << "static " << constexpr_c << " unsigned short propertiesOffset = 2u;\n"; 813 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 2u;\n"; 814 } 815 } else { 816 if (mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, 817 false)) { 818 out << "static " << constexpr_c << " unsigned short propertiesOffset = 1u;\n"; 819 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 0u;\n"; 820 } else { 821 out << "static " << constexpr_c << " unsigned short propertiesOffset = 0u;\n"; 822 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 0u;\n"; 823 } 824 } 825 } else if (mb.getSymmetryType() == mfront::ORTHOTROPIC) { 826 if (mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) { 827 if (mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, 828 false)) { 829 out << "static " << constexpr_c << " unsigned short propertiesOffset = 9u;\n"; 830 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 6u;\n"; 831 } else { 832 out << "static " << constexpr_c << " unsigned short propertiesOffset = 6u;\n"; 833 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 6u;\n"; 834 } 835 } else { 836 if (mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, 837 false)) { 838 out << "static " << constexpr_c << " unsigned short propertiesOffset = 3u;\n"; 839 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 0u;\n"; 840 } else { 841 out << "static " << constexpr_c << " unsigned short propertiesOffset = 0u;\n"; 842 out << "static " << constexpr_c << " unsigned short elasticPropertiesOffset = 0u;\n"; 843 } 844 } 845 } else { 846 tfel::raise( 847 "CyranoInterface::writeCyranoBehaviourTraits: " 848 "unsupported behaviour symmetry type.\n" 849 "The cyrano interface only support isotropic or " 850 "orthotropic behaviour at this time."); 851 } 852 if (mb.getSymmetryType() == mfront::ISOTROPIC) { 853 out << "static " << constexpr_c << " CyranoSymmetryType stype = cyrano::ISOTROPIC;\n"; 854 } else if (mb.getSymmetryType() == mfront::ORTHOTROPIC) { 855 out << "static " << constexpr_c << " CyranoSymmetryType stype = cyrano::ORTHOTROPIC;\n"; 856 } else { 857 tfel::raise( 858 "CyranoInterface::writeCyranoBehaviourTraits: " 859 "unsupported behaviour symmetry type.\n" 860 "The cyrano interface only support isotropic or " 861 "orthotropic behaviour at this time."); 862 } 863 out << "}; // end of class CyranoTraits\n\n"; 864 } // end of CyranoInterface::writeCyranoBehaviourTraits 865 getModellingHypothesisTest(const Hypothesis h) const866 std::string CyranoInterface::getModellingHypothesisTest(const Hypothesis h) const { 867 std::ostringstream test; 868 test << "*NDI==" << this->getModellingHypothesisIdentifier(h); 869 return test.str(); 870 } 871 872 } // end of namespace mfront 873