fmiMEFunctions_int.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. /* line below added during FMU creation */
  2. #include "dlldata_impl.h"
  3. #ifdef _MSC_VER
  4. #include "windows.h"
  5. #include "shlwapi.h"
  6. #endif
  7. #ifndef DYMOLA_STATIC_IMPORT
  8. #define DYMOLA_STATIC_IMPORT DYMOLA_STATIC
  9. #endif
  10. #ifndef FMU_SKIP_MODEL_EXCHANGE
  11. /* The generic implementation of the FMI ME interface. */
  12. /* need to include first so that correct files are included */
  13. #include "conf.h"
  14. #include "util.h"
  15. #include "result.h"
  16. #include "memdebug.h"
  17. #include "fmiFunctions_fwd.h"
  18. #include "dlldata.h"
  19. #include "dymosim.h"
  20. #include <string.h>
  21. #include <assert.h>
  22. /* platform specifics */
  23. #if defined(_MSC_VER) && _MSC_VER >= 1400
  24. /* avoid warnings from Visual Studio */
  25. #define strncpy(dest, src, len) strncpy_s(dest, (len) + 1, src, len)
  26. #endif
  27. /* ----------------- global variables ----------------- */
  28. /* This has 2 purposes:
  29. 1. Detect attempts to create mutliple instances of same FMU.
  30. 2. Direct logging from libds code to FMI logger, when providing FMU with source code.
  31. */
  32. /* when compiling as a single complilation unit, this is already defined */
  33. #ifndef FMU_SOURCE_SINGLE_UNIT
  34. extern Component* globalComponent;
  35. extern Component* globalComponent2;
  36. #endif
  37. /* ----------------- macros ----------------- */
  38. #define ME_RESULT_SAMPLE(atEvent) \
  39. if (comp->storeResult == FMITrue) { \
  40. result_sample(comp, atEvent); \
  41. }
  42. /* ----------------- external function declarations ----------------- */
  43. struct DYNInstanceData;
  44. DYMOLA_STATIC int GetDymolaOneIteration(struct DYNInstanceData*);
  45. DYMOLA_STATIC void SetDymolaOneIteration(struct DYNInstanceData*, int val);
  46. extern void declare_(double*, double*, double*, void**,int*);
  47. /* ----------------- local function declarations ----------------- */
  48. FMIStatus initializeModel(FMIComponent c, FMIBoolean toleranceControlled, FMIReal relativeTolerance, FMIBoolean complete);
  49. /* ----------------- function definitions ----------------- */
  50. /* For 2.0 this is replaced by a common function named fmiGetTypesPlatform_. */
  51. #ifndef FMI_2
  52. DYMOLA_STATIC const char* fmiGetModelTypesPlatform_()
  53. {
  54. return fmiModelTypesPlatform;
  55. }
  56. #endif
  57. /* ---------------------------------------------------------------------- */
  58. #ifndef FMU_SOURCE_SINGLE_UNIT
  59. extern char* GUIDString;
  60. #endif
  61. #endif /* FMU_SKIP_MODEL_EXCHANGE */
  62. struct DYNInstanceDataMinimal {
  63. struct BasicDDymosimStruct*basicD;
  64. struct BasicIDymosimStruct*basicI;
  65. };
  66. DYMOLA_STATIC_IMPORT size_t dyn_allowMultipleInstances;
  67. DYMOLA_STATIC void DYNInitializeDid(struct DYNInstanceData*did_);
  68. DYMOLA_STATIC
  69. #ifdef FMI_2
  70. FMIComponent fmiInstantiateModel_(FMIString instanceName,
  71. FMIString fmuGUID,
  72. FMIString fmuResourceLocation,
  73. const FMICallbackFunctions* functions,
  74. FMIBoolean visible,
  75. FMIBoolean loggingOn)
  76. #else
  77. FMIComponent fmiInstantiateModel_(FMIString instanceName,
  78. FMIString fmuGUID,
  79. fmiMECallbackFunctions functions,
  80. FMIBoolean loggingOn)
  81. #endif /* FMI_2 */
  82. {
  83. static FMIString label = "fmiInstantiateModel";
  84. Component* comp;
  85. size_t i;
  86. int QiErr = 0;
  87. #ifdef FMI_2
  88. const FMICallbackFunctions* funcs = functions;
  89. JacobianData* jacData;
  90. #else
  91. fmiMECallbackFunctions* funcs = &functions;
  92. #endif
  93. if (!dyn_allowMultipleInstances && globalComponent != NULL) {
  94. util_logger(globalComponent, instanceName != NULL ? instanceName : globalComponent->instanceName,
  95. FMIFatal, "", "%s: multiple instances within same process not supported", label);
  96. return NULL;
  97. }
  98. #ifdef MEMLEAK_DEBUG
  99. {
  100. #ifdef FMI_2
  101. FMICallbackFunctions* funcs = (FMICallbackFunctions*) functions;
  102. #else
  103. fmiMECallbackFunctions* funcs = (fmiMECallbackFunctions*) &functions;
  104. #endif
  105. funcs->allocateMemory = memdebug_calloc;
  106. funcs->freeMemory = memdebug_free;
  107. memdebug_setup();
  108. }
  109. #endif
  110. comp = (Component*) funcs->allocateMemory(1 , sizeof(Component));
  111. if (comp == NULL) {
  112. goto fail;
  113. }
  114. if (dyn_allowMultipleInstances) {
  115. comp->did = (struct DYNInstanceData*)funcs->allocateMemory(1, dyn_allowMultipleInstances);
  116. if (comp->did == NULL) {
  117. goto fail;
  118. }
  119. DYNInitializeDid(comp->did);
  120. } else {
  121. comp->did = 0;
  122. }
  123. comp->handles=0;
  124. #ifdef _MSC_VER
  125. {
  126. /* For Loading DLLs from the model. This variant assumes absolute paths and non-wide file names*/
  127. extern const char*dllLibraryPath[];
  128. int numDlls,i,maxLen=0;
  129. if (dllLibraryPath!=0) {
  130. for(numDlls=0;dllLibraryPath[numDlls];++numDlls) {
  131. int stri=(int) strlen(dllLibraryPath[numDlls]);
  132. if (stri>maxLen) maxLen=stri;
  133. }
  134. if (numDlls>0) {
  135. char*s;
  136. extern const char* dymosimFMIPath();
  137. int fmiPathLen = (int) strlen(dymosimFMIPath());
  138. if(fmiPathLen>maxLen) maxLen=fmiPathLen;
  139. comp->handles=(void**)funcs->allocateMemory(numDlls, sizeof(void*));
  140. s=(FMIChar*)funcs->allocateMemory(maxLen+1,sizeof(FMIChar));
  141. if (s==0 || comp->handles==0) goto fail;
  142. for(i=0;i<numDlls;++i) {
  143. comp->handles[i]=0;
  144. strcpy(s,dllLibraryPath[i]);
  145. #if _WIN32_WINNT >= 0x0502
  146. if (s[0]=='.' && s[1]=='\\') {
  147. /* Special handling of local DLLs */
  148. strcpy(s, dymosimFMIPath());
  149. if (s[0]==0) strcpy(s,dllLibraryPath[i]);
  150. }
  151. /* This is the good way */
  152. PathRemoveFileSpecA(s);
  153. SetDllDirectoryA(s);
  154. #endif
  155. comp->handles[i]=(void*)LoadLibraryA(dllLibraryPath[i]);
  156. #if _WIN32_WINNT >= 0x0502
  157. SetDllDirectory(0);
  158. #endif
  159. }
  160. funcs->freeMemory(s);
  161. }
  162. }
  163. }
  164. #endif
  165. /* Initialize to NULL to facilitate freeing om memory */
  166. comp->dstruct = NULL;
  167. comp->istruct = NULL;
  168. comp->states = comp->derivatives = comp->parameters = comp->inputs = comp->outputs = comp->auxiliary =
  169. comp->crossingFunctions = comp->statesNominal = NULL;
  170. comp->isCoSim = FMIFalse; /*Default, change later if Co-Sim*/
  171. /* set sensible default start time */
  172. comp->time = 0;
  173. comp->logbufp = comp->logbuf;
  174. #ifdef FMI_2
  175. comp->functions = funcs;
  176. comp->instanceName = util_strdup(comp->functions, instanceName);
  177. #else
  178. comp->functions.logger = funcs->logger;
  179. comp->functions.allocateMemory = funcs->allocateMemory;
  180. comp->functions.freeMemory = funcs->freeMemory;
  181. comp->instanceName = util_strdup(&comp->functions, instanceName);
  182. #endif
  183. #ifdef FMI_2
  184. //comp->functions.componentEnvironment = funcs->componentEnvironment;
  185. #endif
  186. if (comp->instanceName == NULL) {
  187. goto fail;
  188. }
  189. comp->loggingOn = loggingOn;
  190. /* verify GUID */
  191. if (strcmp(fmuGUID, GUIDString) != 0) {
  192. util_logger(comp, instanceName, FMIError, "", "Invalid GUID: %s, expected %s", fmuGUID, GUIDString);
  193. goto fail;
  194. }
  195. #ifndef FMU_SOURCE_CODE_EXPORT
  196. /* Initialize - which will give a predictable error for missing license (otherwise it will be detected later). Not needed for source code export. */
  197. {
  198. extern int InitializeDymosimRunTime();
  199. if (!InitializeDymosimRunTime()) {
  200. util_logger(comp, instanceName,
  201. FMIFatal, "", "The license file was not found. Use the environment variable \"DYMOLA_RUNTIME_LICENSE\" to specify your Dymola license file.\n");
  202. goto fail;
  203. }
  204. }
  205. #endif
  206. comp->dstruct = (struct BasicDDymosimStruct*) funcs->allocateMemory(1, sizeof(struct BasicDDymosimStruct));
  207. comp->istruct = (struct BasicIDymosimStruct*) funcs->allocateMemory(1, sizeof(struct BasicIDymosimStruct));
  208. if (comp->dstruct == NULL || comp->istruct == NULL) {
  209. goto fail;
  210. }
  211. comp->duser = (double*) comp->dstruct;
  212. comp->iuser = (int*) comp->istruct;
  213. if (comp->did) {
  214. (( struct DYNInstanceDataMinimal*)comp->did)->basicD=comp->dstruct;
  215. (( struct DYNInstanceDataMinimal*)comp->did)->basicI=comp->istruct;
  216. }
  217. setBasicStruct((double*) comp->dstruct, (int*) comp->istruct);
  218. {
  219. int nx, nx2, nu, ny, nw, np, nsp, nrel2, nrel, ncons, dae;
  220. size_t i =0;
  221. GetDimensions2(&nx, &nx2, &nu, &ny, &nw, &np, &nsp, &nrel2, &nrel, &ncons, &dae);
  222. comp->nStates = nx;
  223. comp->nIn = nu;
  224. comp->nOut = ny;
  225. comp->nAux = nw;
  226. comp->nPar = np;
  227. comp->nSPar = nsp;
  228. comp->nCross = 2 * nrel;
  229. /* Guard against zero value for size by adding one */
  230. comp->states = (FMIReal*) funcs->allocateMemory(comp->nStates + 1, sizeof(FMIReal));
  231. comp->derivatives = (FMIReal*) funcs->allocateMemory(comp->nStates + 1, sizeof(FMIReal));
  232. comp->parameters = (FMIReal*) funcs->allocateMemory(comp->nPar + 1, sizeof(FMIReal));
  233. comp->inputs = (FMIReal*) funcs->allocateMemory(comp->nIn + 1, sizeof(FMIReal));
  234. comp->outputs = (FMIReal*) funcs->allocateMemory(comp->nOut + 1, sizeof(FMIReal));
  235. comp->auxiliary = (FMIReal*) funcs->allocateMemory(comp->nAux + 1, sizeof(FMIReal));
  236. comp->crossingFunctions = (FMIReal*) funcs->allocateMemory(comp->nCross + 1, sizeof(FMIReal));
  237. comp->statesNominal = (FMIReal*) funcs->allocateMemory(comp->nStates + 1, sizeof(FMIReal));
  238. comp->sParameters = (FMIChar**) funcs->allocateMemory(comp->nSPar + 1, sizeof(FMIChar*));
  239. comp->oldStates = (FMIReal*) funcs->allocateMemory(comp->nStates+1, sizeof(FMIReal));
  240. }
  241. if (comp->states == NULL || comp->derivatives == NULL || comp->parameters == NULL ||
  242. comp->inputs == NULL || comp->outputs == NULL || comp->auxiliary == NULL ||
  243. comp->crossingFunctions == NULL || comp->statesNominal == NULL || comp->sParameters == NULL) {
  244. goto fail;
  245. }
  246. /*Temporary fmiString pointers to retreve original fmiStrings when calling reset
  247. allocated if needed in reset*/
  248. comp->tsParameters = NULL;
  249. /* no info available, using default values */
  250. for (i = 0; i < comp->nStates; i++) {
  251. comp->statesNominal[i] = 1.0;
  252. }
  253. #ifdef NEW_CODE_GENERATION
  254. /* TODO: */
  255. // assign_real_t(Trivial_variables* v, real_t** p)
  256. // ...
  257. #endif
  258. comp->mStatus = modelInstantiated;
  259. comp->storeResult = FMIFalse;
  260. comp->iData = NULL;
  261. #ifdef FMI_2
  262. jacData = &comp->jacData;
  263. jacData->jacA = jacData->jacB = jacData->jacC = jacData->jacD = NULL;
  264. jacData->jacV = jacData->jacVTmp1 = jacData->jacVTmp2 = jacData->jacZ = jacData->jacZTmp1 = jacData->jacZTmp2 = NULL;
  265. jacData->nJacA = jacData->nJacB = jacData->nJacC = jacData->nJacD = 0;
  266. jacData->nJacV = jacData->nJacZ = 0;
  267. comp->recalJacobian = 1;
  268. #endif
  269. /* FMI API does not require caller to set start values, so must fetch start values for
  270. states and parameters (other variables are initiated by dsblock_) */
  271. declare_(comp->states, comp->parameters, comp->inputs, (void **)comp->sParameters, &QiErr);
  272. for(i=0; i < comp->nSPar; ++i){
  273. FMIString s=(comp->sParameters)[i];
  274. size_t len;
  275. len=strlen(s);
  276. if (len>MAX_STRING_SIZE) len=MAX_STRING_SIZE;
  277. (comp->sParameters)[i] = (FMIChar*) funcs->allocateMemory(MAX_STRING_SIZE+1, sizeof(FMIChar));
  278. memcpy((comp->sParameters)[i], s, len+1);
  279. (comp->sParameters)[i][MAX_STRING_SIZE]='\0';
  280. }
  281. if (QiErr != 0) {
  282. util_logger(comp, comp->instanceName, FMIError, "",
  283. "%s: declare_ failed, QiErr = %d", label, QiErr);
  284. goto fail;
  285. }
  286. /* Default values for setup experiment */
  287. comp->tStart = 0;
  288. comp->StopTimeDefined = FMIFalse;
  289. comp->tStop = 0;
  290. comp->relativeToleranceDefined = FMIFalse;
  291. comp->relativeTolerance = 0;
  292. comp->valWasSet = 0;
  293. if (!dyn_allowMultipleInstances)
  294. globalComponent = comp;
  295. util_logger(comp, comp->instanceName, FMIOK, "", "%s completed", label, QiErr);
  296. return comp;
  297. fail:
  298. if (comp != NULL) {
  299. FMIString iName = instanceName != NULL ? instanceName : "";
  300. util_logger(comp, iName, FMIFatal, "", "Instantiation failed");
  301. fmiFreeModelInstance_(comp);
  302. }
  303. return NULL;
  304. }
  305. /* ---------------------------------------------------------------------- */
  306. DYMOLA_STATIC void fmiFreeModelInstance_(FMIComponent c)
  307. {
  308. Component* comp = (Component*) c;
  309. FMICallbackFreeMemory freeMemory;
  310. #ifdef FMI_2
  311. JacobianData* jacData;
  312. #endif
  313. int i;
  314. if (comp == NULL) {
  315. return;
  316. }
  317. LOG(comp, FMIOK, "fmiFreeModelInstance");
  318. assert(comp->instanceName != NULL);
  319. #ifdef FMI_2
  320. freeMemory = comp->functions->freeMemory;
  321. #else
  322. freeMemory = comp->functions.freeMemory;
  323. #endif
  324. freeMemory((void*) comp->instanceName);comp->instanceName=NULL;
  325. freeMemory(comp->dstruct);comp->dstruct=NULL;
  326. freeMemory(comp->istruct);comp->istruct=NULL;
  327. freeMemory(comp->states);comp->states=NULL;
  328. freeMemory(comp->derivatives);comp->derivatives=NULL;
  329. freeMemory(comp->parameters);comp->parameters=NULL;
  330. freeMemory(comp->inputs);comp->inputs=NULL;
  331. freeMemory(comp->outputs);comp->outputs=NULL;
  332. freeMemory(comp->auxiliary);comp->auxiliary=NULL;
  333. freeMemory(comp->crossingFunctions);comp->crossingFunctions=NULL;
  334. for(i= (int) comp->nSPar-1; i >=0; --i){
  335. freeMemory( (comp->sParameters)[i]);
  336. comp->sParameters[i]=NULL;
  337. }
  338. freeMemory(comp->sParameters);comp->sParameters=NULL;
  339. freeMemory(comp->statesNominal);comp->statesNominal=NULL;
  340. freeMemory(comp->oldStates);comp->oldStates=NULL;
  341. if(comp->tsParameters != NULL){
  342. freeMemory(comp->tsParameters);
  343. comp->tsParameters=NULL;
  344. }
  345. #ifdef FMI_2
  346. jacData = &comp->jacData;
  347. freeMemory(jacData->jacA);jacData->jacA = NULL;
  348. freeMemory(jacData->jacB);jacData->jacB = NULL;
  349. freeMemory(jacData->jacC);jacData->jacC = NULL;
  350. freeMemory(jacData->jacD);jacData->jacD = NULL;
  351. freeMemory(jacData->jacV);jacData->jacV = NULL;
  352. freeMemory(jacData->jacVTmp1);jacData->jacVTmp1 = NULL;
  353. freeMemory(jacData->jacVTmp2);jacData->jacVTmp2 = NULL;
  354. freeMemory(jacData->jacZ);jacData->jacZ = NULL;
  355. freeMemory(jacData->jacZTmp1);jacData->jacZTmp1 = NULL;
  356. freeMemory(jacData->jacZTmp2);jacData->jacZTmp2 = NULL;
  357. #endif /* FMI_2 */
  358. if (comp->handles) {
  359. #ifdef _MSC_VER
  360. extern const char*dllLibraryPath[];
  361. int numDlls,i;
  362. if (dllLibraryPath!=0) {
  363. for(numDlls=0;dllLibraryPath[numDlls];++numDlls);
  364. for(i=0;i<numDlls;++i) {
  365. FreeLibrary(comp->handles[i]);
  366. comp->handles[i]=0;
  367. }
  368. }
  369. #endif
  370. freeMemory(comp->handles);comp->handles = NULL;
  371. }
  372. if (comp->did) {
  373. #ifdef DYN_MULTINSTANCE
  374. extern void EnsureMarkFree2();
  375. EnsureMarkFree2();
  376. #endif
  377. freeMemory(comp->did);
  378. comp->did=NULL;
  379. }
  380. freeMemory(comp);comp = NULL;
  381. if (!dyn_allowMultipleInstances) {
  382. assert(globalComponent == c || globalComponent == NULL);
  383. globalComponent = NULL;
  384. }
  385. #ifndef FMU_SOURCE_CODE_EXPORT
  386. {
  387. extern void UnInitializeDymosimRunTime();
  388. UnInitializeDymosimRunTime();
  389. }
  390. #endif
  391. #ifdef MEMLEAK_DEBUG
  392. memdebug_check();
  393. #endif
  394. }
  395. /* ---------------------------------------------------------------------- */
  396. DYMOLA_STATIC FMIStatus fmiSetTime_(FMIComponent c, FMIReal time)
  397. {
  398. static FMIString label = "fmiSetTime";
  399. Component* comp = (Component*) c;
  400. /* avoid cluttering the code with check if time == comp->time to handle odd uses of this function
  401. what complicates it is that if in modelEventModeExit, even same time should be considered */
  402. #ifdef FMI_2
  403. if (comp->mStatus == modelEventModeExit) {
  404. if (comp->nStates != 0) {
  405. util_logger(comp, comp->instanceName, FMIWarning, "", "%s: only allowed for discrete models when not in continuous time mode", label);
  406. return FMIWarning;
  407. }
  408. /* resuse this mode also to discrete models for convenience */
  409. comp->mStatus = modelContinousTimeMode;
  410. } else if (comp->mStatus != modelContinousTimeMode && comp->mStatus != modelInstantiated) {
  411. util_logger(comp, comp->instanceName, FMIWarning, "", "%s: not allowed in this state", label);
  412. return FMIWarning;
  413. }
  414. #endif
  415. comp->time = time;
  416. comp->icall = iDemandStart;
  417. comp->recalJacobian = 1;
  418. util_logger(comp, comp->instanceName, FMIOK, "", "%s to %g", label, time);
  419. return FMIOK;
  420. }
  421. #ifndef FMU_SKIP_MODEL_EXCHANGE
  422. /* ---------------------------------------------------------------------- */
  423. DYMOLA_STATIC FMIStatus fmiSetContinuousStates_(FMIComponent c, const FMIReal x[], size_t nx)
  424. {
  425. static FMIString label = "fmiSetContinuousStates";
  426. Component* comp = (Component*) c;
  427. FMIStatus status = FMIOK;
  428. if (nx != comp->nStates) {
  429. status = FMIWarning;
  430. util_logger(comp, comp->instanceName, status, "",
  431. "fmiSetContinuousStates: argument nx = %u is incorrect, should be %u", nx, comp->nStates);
  432. if (nx > comp->nStates) {
  433. /* truncate */
  434. nx = comp->nStates;
  435. }
  436. }
  437. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  438. memcpy(comp->states, x, nx * sizeof(FMIReal));
  439. /* reset caching */
  440. comp->valWasSet = 1;
  441. comp->icall = iDemandStart;
  442. comp->recalJacobian = 1;
  443. return status;
  444. }
  445. #endif /* FMU_SKIP_MODEL_EXCHANGE */
  446. #ifdef FMI_2
  447. /* ---------------------------------------------------------------------- */
  448. DYMOLA_STATIC FMIStatus fmiEnterModelInitializationMode_(FMIComponent c, FMIBoolean toleranceControlled, FMIReal relativeTolerance)
  449. {
  450. static FMIString label = "fmiEnterModelInitializationMode";
  451. Component* comp = (Component*) c;
  452. FMIStatus status;
  453. util_logger(comp, comp->instanceName, FMIOK, "", "%s...", label);
  454. status = util_initialize_model(c, toleranceControlled, relativeTolerance, FMIFalse);
  455. if (status != FMIOK) {
  456. return status;
  457. }
  458. comp->mStatus = modelInitializationMode;
  459. util_logger(comp, comp->instanceName, FMIOK, "", "%s completed", label);
  460. return status;
  461. }
  462. /* ---------------------------------------------------------------------- */
  463. DYMOLA_STATIC FMIStatus fmiExitModelInitializationMode_(FMIComponent c)
  464. {
  465. static FMIString label = "fmiExitModelInitializationMode";
  466. Component* comp = (Component*) c;
  467. FMIStatus status;
  468. util_logger(comp, comp->instanceName, FMIOK, "", "%s...", label);
  469. status = util_exit_model_initialization_mode(c, label, modelEventMode);
  470. comp->firstEventCall=FMITrue;
  471. if (status != FMIOK) {
  472. return status;
  473. }
  474. util_logger(comp, comp->instanceName, FMIOK, "", "%s completed", label);
  475. return FMIOK;
  476. }
  477. #else /* FMI_2 */
  478. /* ---------------------------------------------------------------------- */
  479. DYMOLA_STATIC FMIStatus fmiInitialize_ (FMIComponent c, FMIBoolean toleranceControlled, FMIReal relativeTolerance, FMIEventInfo* eventInfo)
  480. {
  481. static FMIString label = "fmiInitialize";
  482. Component* comp = (Component*) c;
  483. FMIStatus status;
  484. // for co-simulation, this initialization is only a subset
  485. if (!comp->isCoSim) {
  486. util_logger(comp, comp->instanceName, FMIOK, "", "%s...", label);
  487. }
  488. status = util_initialize_model(c, toleranceControlled, relativeTolerance, FMITrue);
  489. if (status != fmiOK ) {
  490. return status;
  491. }
  492. eventInfo->terminateSimulation = FMIFalse;
  493. eventInfo->upcomingTimeEvent = (comp->dstruct->mNextTimeEvent < TIME_INFINITY) ? FMITrue : FMIFalse;
  494. if (eventInfo->upcomingTimeEvent == FMITrue) {
  495. eventInfo->nextEventTime = comp->dstruct->mNextTimeEvent;
  496. }
  497. // for co-simulation, this initialization is only a subset
  498. if (!comp->isCoSim) {
  499. comp->mStatus = modelContinousTimeMode;
  500. util_logger(comp, comp->instanceName, status, "", "%s completed", label);
  501. }
  502. comp->eventIterationOnGoing = 0;
  503. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  504. return FMIOK;
  505. }
  506. #endif /* FMI_2 */
  507. #ifndef FMU_SKIP_MODEL_EXCHANGE
  508. #ifdef FMI_2
  509. /* ---------------------------------------------------------------------- */
  510. DYMOLA_STATIC FMIStatus fmiEnterEventMode_(FMIComponent c)
  511. {
  512. static FMIString label = "fmiEnterEventMode";
  513. Component* comp = (Component*) c;
  514. util_logger(comp, comp->instanceName, FMIOK, "", "%s...", label);
  515. if (comp->mStatus != modelContinousTimeMode) {
  516. util_logger(comp, comp->instanceName, FMIWarning, "", "%s: may only be called in continuous time mode", label);
  517. return FMIWarning;
  518. }
  519. comp->mStatus = modelEventMode;
  520. comp->firstEventCall = FMITrue;
  521. util_logger(comp, comp->instanceName, FMIOK, "", "%s done", label);
  522. return FMIOK;
  523. }
  524. /* ---------------------------------------------------------------------- */
  525. DYMOLA_STATIC FMIStatus fmiEnterContinuousTimeMode_(FMIComponent c)
  526. {
  527. static FMIString label = "fmiEnterContinuousTimeMode";
  528. Component* comp = (Component*) c;
  529. util_logger(comp, comp->instanceName, FMIOK, "", "%s...", label);
  530. if (comp->mStatus != modelEventModeExit) {
  531. util_logger(comp, comp->instanceName, FMIWarning, "", "%s: may only be called when exited event mode", label);
  532. return FMIWarning;
  533. }
  534. ME_RESULT_SAMPLE(FMITrue);
  535. comp->mStatus = modelContinousTimeMode;
  536. util_logger(comp, comp->instanceName, FMIOK, "", "%s done", label);
  537. return FMIOK;
  538. }
  539. /* ---------------------------------------------------------------------- */
  540. DYMOLA_STATIC FMIStatus fmiNewDiscreteStates_(FMIComponent c, FMIEventInfo* eventInfo)
  541. {
  542. static FMIString label = "fmiNewDiscreteStates";
  543. Component* comp = (Component*) c;
  544. FMIStatus status = FMIOK;
  545. int QiErr = 0;
  546. FMIBoolean converged = 0;
  547. size_t i = 0;
  548. util_logger(comp, comp->instanceName, FMIOK, "", "%s...", label);
  549. /* for co-simulation, sampling is handled at higher level */
  550. if (comp->isCoSim == FMIFalse) {
  551. ME_RESULT_SAMPLE(FMITrue);
  552. }
  553. memcpy(comp->oldStates,comp->states, comp->nStates*sizeof(FMIReal));
  554. if(comp->nStates == 0 && comp->mStatus == modelContinousTimeMode){
  555. comp->mStatus = modelEventMode;
  556. }
  557. /* configure actual event iteration */
  558. switch (comp->mStatus) {
  559. case modelEventModeExit:
  560. /* allowed to restart the event iteration again */
  561. comp->mStatus = modelEventMode;
  562. /* fall-through */
  563. case modelEventMode:
  564. case modelEventMode2:
  565. if(comp->valWasSet && !comp->firstEventCall){
  566. SetDymolaOneIteration(comp->did, 5);
  567. QiErr = util_refresh_cache(comp, iDemandEventHandling, NULL, &converged);
  568. if (QiErr != 0) {
  569. goto eventDone;
  570. }
  571. }
  572. SetDymolaOneIteration(comp->did, 3);
  573. break;
  574. default:
  575. util_logger(comp, comp->instanceName, FMIWarning, "", "%s: may only be called in event mode", label);
  576. return FMIWarning;
  577. }
  578. comp->icall = 0;
  579. QiErr = util_refresh_cache(comp, iDemandEventHandling, NULL, &converged);
  580. eventDone:
  581. eventInfo->valuesOfContinuousStatesChanged = FMIFalse;
  582. for (i=0; i<comp->nStates; ++i){
  583. if(comp->states[i] != comp->oldStates[i]){
  584. eventInfo->valuesOfContinuousStatesChanged = FMITrue;
  585. }
  586. }
  587. if (QiErr != 0) {
  588. if (QiErr == -999) {
  589. util_logger(comp, comp->instanceName, FMIOK, "", "%s: simulation terminated by model", label);
  590. eventInfo->terminateSimulation = FMITrue;
  591. eventInfo->newDiscreteStatesNeeded = FMIFalse;
  592. eventInfo->nominalsOfContinuousStatesChanged= FMIFalse;
  593. //eventInfo->valuesOfContinuousStatesChanged = (comp->nStates > 0) ? FMITrue : FMIFalse;
  594. eventInfo->nextEventTimeDefined = FMIFalse;
  595. eventInfo->nextEventTime = 1.0e37;
  596. comp->mStatus = modelEventModeExit;
  597. comp->terminationByModel = FMITrue;
  598. return FMIOK;
  599. } else {
  600. util_logger(comp, comp->instanceName, FMIError, "",
  601. "%s: dsblock_ failed, QiErr = %d", label, QiErr);
  602. return util_error(comp);
  603. }
  604. }
  605. if (converged == FMIFalse)
  606. {
  607. eventInfo->newDiscreteStatesNeeded = FMITrue;
  608. comp->mStatus = modelEventMode2;
  609. comp->eventIterRequired = 1;
  610. } else {
  611. eventInfo->newDiscreteStatesNeeded = FMIFalse;
  612. comp->mStatus = modelEventModeExit;
  613. comp->eventIterRequired = 0;
  614. }
  615. eventInfo->terminateSimulation = FMIFalse;
  616. eventInfo->nominalsOfContinuousStatesChanged= FMIFalse;
  617. eventInfo->nextEventTimeDefined = (comp->dstruct->mNextTimeEvent < (1.0E37 - 1)) ? FMITrue : FMIFalse;
  618. if (eventInfo->nextEventTimeDefined == FMITrue) {
  619. eventInfo->nextEventTime = comp->dstruct->mNextTimeEvent;
  620. }
  621. comp->recalJacobian = 1;
  622. util_logger(comp, comp->instanceName, FMIOK, "", "%s completed", label);
  623. return FMIOK;
  624. }
  625. #else
  626. DYMOLA_STATIC FMIStatus fmiEventUpdate_(FMIComponent c, FMIBoolean intermediateResults, FMIEventInfo* eventInfo)
  627. {
  628. static FMIString label = "fmiEventUpdate";
  629. Component* comp = (Component*) c;
  630. FMIStatus status = FMIOK;
  631. int QiErr = 0;
  632. FMIBoolean converged = 0;
  633. util_logger(comp, comp->instanceName, FMIOK, "", "%s...", label);
  634. if (comp->mStatus != modelContinousTimeMode) {
  635. util_logger(comp, comp->instanceName, FMIWarning, "",
  636. "%s: initialization must be done before event updating is allowed", label);
  637. return FMIWarning;
  638. }
  639. ME_RESULT_SAMPLE(FMITrue);
  640. status = util_event_update(c, intermediateResults, eventInfo);
  641. if (status == FMIError) {
  642. return util_error(comp);
  643. } else if (status == FMIFatal) {
  644. return FMIFatal;
  645. }
  646. util_logger(comp, comp->instanceName, FMIOK, "", "%s completed", label);
  647. return status;
  648. }
  649. #endif /* FMI_2 */
  650. /* ---------------------------------------------------------------------- */
  651. DYMOLA_STATIC FMIStatus fmiCompletedIntegratorStep_(FMIComponent c,
  652. #ifdef FMI_2
  653. FMIBoolean noSetFMUStatePriorToCurrentPoint,
  654. FMIBoolean* enterEventMode,
  655. FMIBoolean* terminateSimulation)
  656. #else
  657. FMIBoolean* callEventUpdate)
  658. #endif
  659. {
  660. static FMIString label = "fmiCompletedIntegratorStep";
  661. Component* comp = (Component*) c;
  662. ME_RESULT_SAMPLE(FMIFalse);
  663. #ifdef FMI_2
  664. if (comp->storeResult == FMITrue) {
  665. if (noSetFMUStatePriorToCurrentPoint) {
  666. result_flush(comp);
  667. }
  668. }
  669. *terminateSimulation = comp->terminationByModel;
  670. /* only applies to step event */
  671. *enterEventMode = comp->istruct->mTriggerStepEvent ? FMITrue : FMIFalse;
  672. #else
  673. *callEventUpdate = comp->istruct->mTriggerStepEvent ? FMITrue : FMIFalse;
  674. #endif
  675. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  676. return FMIOK;
  677. }
  678. #endif /* FMU_SKIP_MODEL_EXCHANGE */
  679. /* ---------------------------------------------------------------------- */
  680. extern void delayBuffersClose(void);
  681. extern void delayBuffersCloseNew(struct DYNInstanceData*);
  682. #ifdef FMI_2
  683. DYMOLA_STATIC FMIStatus fmiTerminateModel_(FMIComponent c)
  684. #else
  685. DYMOLA_STATIC FMIStatus fmiTerminate_(FMIComponent c)
  686. #endif
  687. {
  688. #ifdef FMI_2
  689. static FMIString label = "fmi2Terminate";
  690. #else
  691. static FMIString label = "fmiTerminate";
  692. #endif
  693. Component* comp = (Component*) c;
  694. FMIStatus status = FMIOK;
  695. if (comp->mStatus == modelTerminated) {
  696. util_logger(comp, comp->instanceName, FMIWarning, "", "%s: already terminated, ignoring call", label);
  697. return FMIWarning;
  698. }
  699. if (!comp->isCoSim) {
  700. LOG(comp, FMIOK, label);
  701. if(comp->QiErr == 0 && comp->terminationByModel == FMIFalse){
  702. /*Special case for terminal, call dsblock_ directly instead of
  703. using util_refresh_cache to avoid messy logic*/
  704. int terminal = iDemandTerminal;
  705. if (comp->did) {
  706. globalComponent2=comp;
  707. dsblock_tid(&terminal, &comp->icall, &comp->time, comp->states, 0,
  708. comp->inputs, comp->parameters, 0, 0, comp->derivatives,
  709. comp->outputs, comp->auxiliary,
  710. comp->crossingFunctions, comp->duser, comp->iuser,
  711. (void**) comp->sParameters, comp->did, &comp->QiErr, 0);
  712. globalComponent2=0;
  713. } else {
  714. dsblock_(&terminal, &comp->icall, &comp->time, comp->states, 0,
  715. comp->inputs, comp->parameters, 0, 0, comp->derivatives,
  716. comp->outputs, comp->auxiliary,
  717. comp->crossingFunctions, comp->duser, comp->iuser,
  718. (void**) comp->sParameters, &comp->QiErr);
  719. }
  720. if (comp->QiErr>=-995 && comp->QiErr<=-990) comp->QiErr=0; /* Ignore special cases for now */
  721. if(!(comp->QiErr == 0 || comp->QiErr==-999)){
  722. status = FMIError;
  723. util_logger(comp, comp->instanceName, FMIError, "",
  724. "%s: calling terminal section of dsblock_ failed, QiErr = %d",
  725. label,comp->QiErr);
  726. }
  727. }
  728. }
  729. util_print_dymola_timers(c);
  730. #ifndef FMU_SOURCE_CODE_EXPORT
  731. if (comp->storeResult == FMITrue) {
  732. result_teardown(comp);
  733. }
  734. #endif /* FMU_SOURCE_CODE_EXPORT */
  735. if (comp->did) {
  736. delayBuffersCloseNew(comp->did);
  737. } else {
  738. delayBuffersClose();
  739. }
  740. comp->mStatus = modelTerminated;
  741. return status;
  742. }
  743. /* ---------------------------------------------------------------------- */
  744. DYMOLA_STATIC FMIStatus fmiGetDerivatives_(FMIComponent c, FMIReal derivatives[], size_t nx)
  745. {
  746. static FMIString label = "fmiGetDerivatives";
  747. Component* comp = (Component*) c;
  748. FMIStatus status = FMIOK;
  749. int QiErr = 0;
  750. if( comp->mStatus == modelInstantiated){
  751. util_logger(comp, comp->instanceName, FMIWarning, "",
  752. #ifdef FMI_2
  753. "%s: fmiEnterInitializationMode must be called before calling %s", label, label);
  754. #else
  755. "%s: fmiInitializeModel must be called before calling %s", label, label);
  756. #endif
  757. return FMIWarning;
  758. }
  759. if (nx != comp->nStates) {
  760. status = FMIWarning;
  761. util_logger(comp, comp->instanceName, status, "",
  762. "%s: argument nx = %u is incorrect, should be %u", label, nx, comp->nStates);
  763. if (nx > comp->nStates) {
  764. /* truncate */
  765. nx = comp->nStates;
  766. }
  767. }
  768. if (comp->icall < iDemandDerivative) {
  769. /* refresh cache */
  770. int QiErr = util_refresh_cache(comp, iDemandDerivative, label, NULL);
  771. if (QiErr != 0) {
  772. return (QiErr == 1) ? FMIDiscard : util_error(comp);
  773. }
  774. }
  775. memcpy(derivatives, comp->derivatives, nx * sizeof(FMIReal));
  776. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  777. return status;
  778. }
  779. /* ---------------------------------------------------------------------- */
  780. DYMOLA_STATIC FMIStatus fmiGetEventIndicators_(FMIComponent c, FMIReal eventIndicators[], size_t ni)
  781. {
  782. static FMIString label = "fmiGetEventIndicators";
  783. Component* comp = (Component*) c;
  784. FMIStatus status = FMIOK;
  785. if( comp->mStatus == modelInstantiated ||comp->mStatus == modelInitializationMode){
  786. util_logger(comp, comp->instanceName, FMIWarning, "",
  787. #ifdef FMI_2
  788. "%s: fmiExitInitializationMode must be called before calling %s", label, label);
  789. #else
  790. "%s: fmiInitializeModel must be called before calling %s", label, label);
  791. #endif
  792. return FMIWarning;
  793. }
  794. if (ni != comp->nCross) {
  795. status = FMIWarning;
  796. util_logger(comp, comp->instanceName, status, "",
  797. "%s: argument ni = %u is incorrect, should be %u", label, ni, comp->nCross);
  798. if (ni > comp->nCross) {
  799. /* truncate */
  800. ni = comp->nCross;
  801. }
  802. }
  803. if (comp->icall < iDemandCrossingFunction) {
  804. /* refresh cache */
  805. int QiErr = util_refresh_cache(comp, iDemandCrossingFunction, label, NULL);
  806. if (QiErr != 0) {
  807. return (QiErr == 1) ? FMIDiscard : util_error(comp);
  808. }
  809. }
  810. memcpy(eventIndicators, comp->crossingFunctions, ni * sizeof(FMIReal));
  811. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  812. return status;
  813. }
  814. #ifndef FMU_SKIP_MODEL_EXCHANGE
  815. /* ---------------------------------------------------------------------- */
  816. DYMOLA_STATIC FMIStatus fmiGetContinuousStates_(FMIComponent c, FMIReal states[], size_t nx)
  817. {
  818. static FMIString label = "fmiGetContinuousStates";
  819. Component* comp = (Component*) c;
  820. FMIStatus status = FMIOK;
  821. #ifdef FMI_2
  822. if( comp->mStatus == modelInstantiated){
  823. util_logger(comp, comp->instanceName, FMIWarning, "",
  824. "%s: fmiEnterInitializationMode must be called before calling %s", label, label);
  825. return FMIWarning;
  826. }
  827. #endif
  828. if (nx != comp->nStates) {
  829. status = FMIWarning;
  830. util_logger(comp, comp->instanceName, status, "",
  831. "%s: argument nx = %u is incorrect, should be %u", label, nx, comp->nStates);
  832. if (nx > comp->nStates) {
  833. /* truncate */
  834. nx = comp->nStates;
  835. }
  836. }
  837. memcpy(states, comp->states, nx * sizeof(FMIReal));
  838. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  839. return status;
  840. }
  841. /* ---------------------------------------------------------------------- */
  842. #ifdef FMI_2
  843. DYMOLA_STATIC FMIStatus fmiGetNominalsOfContinuousStates_(FMIComponent c, FMIReal x_nominal[], size_t nx) {
  844. static FMIString label = "fmiGetNominalsOfContinuousStates";
  845. #else
  846. DYMOLA_STATIC FMIStatus fmiGetNominalContinuousStates_(FMIComponent c, FMIReal x_nominal[], size_t nx) {
  847. static FMIString label = "fmiGetNominalContinuousStates";
  848. #endif
  849. Component* comp = (Component*) c;
  850. FMIStatus status = FMIOK;
  851. if (nx != comp->nStates) {
  852. status = FMIWarning;
  853. util_logger(comp, comp->instanceName, status, "",
  854. "%s: argument nx = %u is incorrect, should be %u", label, nx, comp->nStates);
  855. if (nx > comp->nStates) {
  856. /* truncate */
  857. nx = comp->nStates;
  858. }
  859. }
  860. memcpy(x_nominal, comp->statesNominal, nx * sizeof(FMIReal));
  861. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  862. return status;
  863. }
  864. #ifndef FMI_2
  865. /* ---------------------------------------------------------------------- */
  866. DYMOLA_STATIC FMIStatus fmiGetStateValueReferences_(FMIComponent c, FMIValueReference vrx[], size_t nx)
  867. {
  868. static FMIString label = "fmiGetStateValueReferences";
  869. Component* comp = (Component*) c;
  870. FMIStatus status = FMIOK;
  871. size_t i;
  872. if (nx != comp->nStates) {
  873. status = FMIWarning;
  874. util_logger(comp, comp->instanceName, status, "",
  875. "%s: argument nx = %u is incorrect, should be %u", label, nx, comp->nStates);
  876. if (nx > comp->nStates) {
  877. /* truncate */
  878. nx = comp->nStates;
  879. }
  880. }
  881. for (i = 0; i < nx; i++) {
  882. #ifndef FMU_SOURCE_SINGLE_UNIT
  883. extern unsigned int FMIStateValueReferences_[];
  884. #endif
  885. vrx[i] = FMIStateValueReferences_[i];
  886. }
  887. util_logger(comp, comp->instanceName, FMIOK, "", "%s", label);
  888. return status;
  889. }
  890. #endif /* FMI_2 */
  891. #endif /* FMU_SKIP_MODEL_EXCHANGE */