nonlinearValuesList.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /*
  2. * This file is part of OpenModelica.
  3. *
  4. * Copyright (c) 1998-CurrentYear, Linköping University,
  5. * Department of Computer and Information Science,
  6. * SE-58183 Linköping, Sweden.
  7. *
  8. * All rights reserved.
  9. *
  10. * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3
  11. * AND THIS OSMC PUBLIC LICENSE (OSMC-PL).
  12. * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
  13. * ACCEPTANCE OF THE OSMC PUBLIC LICENSE.
  14. *
  15. * The OpenModelica software and the Open Source Modelica
  16. * Consortium (OSMC) Public License (OSMC-PL) are obtained
  17. * from Linköping University, either from the above address,
  18. * from the URLs: http://www.ida.liu.se/projects/OpenModelica or
  19. * http://www.openmodelica.org, and in the OpenModelica distribution.
  20. * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
  21. *
  22. * This program is distributed WITHOUT ANY WARRANTY; without
  23. * even the implied warranty of MERCHANTABILITY or FITNESS
  24. * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
  25. * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS
  26. * OF OSMC-PL.
  27. *
  28. * See the full OSMC Public License conditions for more details.
  29. *
  30. */
  31. /*! \file nonlinearValuesList.h
  32. * Description: This is a C implementation of a value database
  33. * based on a list. It's purpose is to be used by a
  34. * a non-linear solver in OpenModelica in order to
  35. * guess next value by extrapolation or interpolation.
  36. * Assuming time passes forward.
  37. *
  38. */
  39. #include "nonlinearValuesList.h"
  40. #include "util/list.h"
  41. #include "util/omc_error.h"
  42. #include <stdlib.h>
  43. #include <string.h>
  44. /* Forward extrapolate function definition */
  45. double extrapolateValues(const double, const double, const double, const double, const double);
  46. VALUES_LIST* allocValueList(unsigned int numberOfList)
  47. {
  48. unsigned int i = 0;
  49. VALUES_LIST* valueList = (VALUES_LIST*) malloc(numberOfList*sizeof(VALUES_LIST));
  50. for(i=0; i<numberOfList; ++i){
  51. (valueList+i)->valueList = allocList(sizeof(VALUE));
  52. }
  53. return valueList;
  54. }
  55. void freeValueList(VALUES_LIST *valueList, unsigned int numberOfList)
  56. {
  57. VALUE* elem;
  58. VALUES_LIST *tmpList;
  59. int i,j;
  60. for(j = 0; j < numberOfList; ++j)
  61. {
  62. tmpList = valueList+j;
  63. for(i = 0; i < listLen(tmpList->valueList); ++i)
  64. {
  65. elem = (VALUE*) listFirstData(tmpList->valueList);
  66. listPopFront(tmpList->valueList);
  67. }
  68. freeList(tmpList->valueList);
  69. }
  70. free(valueList);
  71. }
  72. void cleanValueList(VALUES_LIST *valueList, LIST_NODE *startNode)
  73. {
  74. LIST_NODE *next, *node;
  75. VALUE* elem;
  76. int i, j;
  77. if (startNode == NULL)
  78. {
  79. listClear(valueList->valueList);
  80. }
  81. else
  82. {
  83. next = listNextNode(startNode);
  84. /* clean list from next node */
  85. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "cleanValueList length: %d", listLen(valueList->valueList));
  86. updateNodeNext(valueList->valueList, startNode, NULL);
  87. removeNodes(valueList->valueList, next);
  88. }
  89. }
  90. void cleanValueListbyTime(VALUES_LIST *valueList, double time)
  91. {
  92. LIST_NODE *next, *node;
  93. VALUE* elem;
  94. /* if it's empty anyway */
  95. if (listLen(valueList->valueList) == 0)
  96. {
  97. return;
  98. }
  99. printValuesListTimes(valueList);
  100. node = listFirstNode(valueList->valueList);
  101. do
  102. {
  103. elem = ((VALUE*)listNodeData(node));
  104. next = listNextNode(node);
  105. /* if next node is empty */
  106. if (!next)
  107. {
  108. return;
  109. }
  110. if (elem->time <= time)
  111. {
  112. break;
  113. }
  114. /* debug output */
  115. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "cleanValueListbyTime %g check element: ", time);
  116. printValueElement(elem);
  117. freeNode(node);
  118. updatelistFirst(valueList->valueList, next);
  119. updatelistLength(valueList->valueList, listLen(valueList->valueList)-1);
  120. node = next;
  121. }while(1);
  122. cleanValueList(valueList, node);
  123. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "New list length %d: ", listLen(valueList->valueList));
  124. printValuesListTimes(valueList);
  125. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Done!");
  126. }
  127. VALUE* createValueElement(unsigned int size, double time, double* values)
  128. {
  129. VALUE* elem = (VALUE*) malloc(sizeof(VALUE));
  130. elem->values = (double*) malloc(size*sizeof(double));
  131. elem->time = time;
  132. elem->size = size;
  133. memcpy(elem->values, values, size*sizeof(double));
  134. /* debug output */
  135. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 1, "Create Element");
  136. messageClose(LOG_NLS_EXTRAPOLATE);
  137. return elem;
  138. }
  139. void freeValue(VALUE* elem)
  140. {
  141. free(elem->values);
  142. free(elem);
  143. }
  144. void addListElement(VALUES_LIST* valuesList, VALUE* newElem)
  145. {
  146. LIST_NODE *node, *next;
  147. VALUE* elem;
  148. int replace = 0, i = 0;
  149. /* debug output */
  150. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 1, "Adding element in a list of size %d", listLen(valuesList->valueList));
  151. printValueElement(newElem);
  152. /* if it's empty, just push in */
  153. if (listLen(valuesList->valueList) == 0)
  154. {
  155. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "List is empty add just.");
  156. listPushFront(valuesList->valueList, (void*) newElem);
  157. messageClose(LOG_NLS_EXTRAPOLATE);
  158. return;
  159. }
  160. /* if the element at begin is earlier than current
  161. * push the element just in front and if the end element
  162. * is later than current push it just back.*/
  163. node = listFirstNode(valuesList->valueList);
  164. if (((VALUE*)listNodeData(node))->time < newElem->time)
  165. {
  166. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "First Value list element is:");
  167. printValueElement(((VALUE*)listNodeData(node)));
  168. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "so new element is added before.");
  169. listPushFront(valuesList->valueList, (void*) newElem);
  170. messageClose(LOG_NLS_EXTRAPOLATE);
  171. return;
  172. }
  173. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Search position of new element");
  174. /* search correct position */
  175. next = node;
  176. do
  177. {
  178. /* if next node is empty */
  179. if (!next)
  180. {
  181. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Search finished last element reached");
  182. break;
  183. }
  184. elem = ((VALUE*)listNodeData(next));
  185. /* debug output */
  186. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Next node of list is element:");
  187. printValueElement(elem);
  188. if (elem->time < newElem->time)
  189. {
  190. break;
  191. }
  192. else if (elem->time == newElem->time)
  193. {
  194. replace = 1;
  195. break;
  196. }
  197. node = next;
  198. next = listNextNode(node);
  199. i++; /* count insert or replace place */
  200. }while(1);
  201. /* add element before currect node */
  202. if (!replace){
  203. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Insert element before last output element.");
  204. listInsert(valuesList->valueList, node, (void*) newElem);
  205. }
  206. else
  207. {
  208. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "replace element.");
  209. updateNodeData(valuesList->valueList, next, (void*) newElem);
  210. }
  211. /* clean list if too full */
  212. if (i < 3 && listLen(valuesList->valueList)>10)
  213. {
  214. while(i < 4)
  215. {
  216. next = listNextNode(next);
  217. i++;
  218. }
  219. cleanValueList(valuesList, next);
  220. }
  221. messageClose(LOG_NLS_EXTRAPOLATE);
  222. return;
  223. }
  224. void getValues(VALUES_LIST* valuesList, double time, double* extrapolatedValues, double* oldOutput)
  225. {
  226. LIST_NODE *begin, *next, *old, *old2;
  227. VALUE *oldValues, *old2Values, *elem;
  228. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 1, "Get values for time %g in a list of size %d", time, listLen(valuesList->valueList));
  229. begin = listFirstNode(valuesList->valueList);
  230. assertStreamPrint(NULL, NULL != begin, "getValues failed, no elements");
  231. /* find corresponding values */
  232. do{
  233. elem = (VALUE*)listNodeData(begin);
  234. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Searching current element:");
  235. printValueElement(elem);
  236. if (elem->time == time)
  237. {
  238. old = begin;
  239. old2 = NULL;
  240. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "take element with the same time.");
  241. break;
  242. }
  243. else if (elem->time < time)
  244. {
  245. old = begin;
  246. old2 = listNextNode(old);
  247. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "found element to use for extrapolation.");
  248. break;
  249. }
  250. else
  251. {
  252. next = listNextNode(begin);
  253. if (!next){
  254. old = begin;
  255. old2 = next;
  256. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "reached end of list.");
  257. break;
  258. }
  259. else
  260. {
  261. begin = next;
  262. }
  263. }
  264. }while(1);
  265. /* get next values */
  266. if (old2 == NULL)
  267. {
  268. oldValues = (VALUE*) listNodeData(old);
  269. memcpy(extrapolatedValues, oldValues->values, oldValues->size*sizeof(double));
  270. memcpy(oldOutput, oldValues->values, oldValues->size*sizeof(double));
  271. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "take just old values.");
  272. }
  273. else
  274. {
  275. int i;
  276. oldValues = (VALUE*) listNodeData(old);
  277. old2Values = (VALUE*) listNodeData(old2);
  278. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Use following elements for calculation:");
  279. printValueElement(oldValues);
  280. printValueElement(old2Values);
  281. for(i = 0; i < oldValues->size; ++i)
  282. {
  283. extrapolatedValues[i] = extrapolateValues(time, oldValues->values[i], oldValues->time, old2Values->values[i], old2Values->time);
  284. }
  285. memcpy(oldOutput, oldValues->values, oldValues->size*sizeof(double));
  286. }
  287. messageClose(LOG_NLS_EXTRAPOLATE);
  288. return;
  289. }
  290. void printValueElement(VALUE* elem)
  291. {
  292. /* debug output */
  293. if(ACTIVE_STREAM(LOG_NLS_EXTRAPOLATE))
  294. {
  295. int i;
  296. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 1, "Element(size %d) at time %g ", elem->size, elem->time);
  297. for(i = 0; i < elem->size; i++) {
  298. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, " oldValues[%d] = %g",i, elem->values[i]);
  299. }
  300. messageClose(LOG_NLS_EXTRAPOLATE);
  301. }
  302. }
  303. void printValuesListTimes(VALUES_LIST* list)
  304. {
  305. /* debug output */
  306. if(ACTIVE_STREAM(LOG_NLS_EXTRAPOLATE))
  307. {
  308. int i;
  309. LIST_NODE *next;
  310. VALUE *elem;
  311. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 1, "Print all elements");
  312. if (listLen(list->valueList) == 0){
  313. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "List is empty!");
  314. messageClose(LOG_NLS_EXTRAPOLATE);
  315. return;
  316. }
  317. next = listFirstNode(list->valueList);
  318. assertStreamPrint(NULL, NULL != next, "printValuesListTimes failed, no elements");
  319. /* go though the list */
  320. for(i = 0; i < listLen(list->valueList); i++) {
  321. elem = (VALUE*)listNodeData(next);
  322. infoStreamPrint(LOG_NLS_EXTRAPOLATE, 0, "Element %d at time %g", i, elem->time);
  323. next = listNextNode(next);
  324. }
  325. messageClose(LOG_NLS_EXTRAPOLATE);
  326. }
  327. }
  328. /*! \fn extraPolateValues
  329. * This function extrapolates linear values based on old values.
  330. *
  331. * \param [in] [time] desired time for extrapolation
  332. * \param [in] [old1] old value at time1
  333. * \param [in] [time1] time for the first value
  334. * \param [in] [old2] old value at time2
  335. * \param [in] [time2] time for the second value
  336. */
  337. double extrapolateValues(const double time, const double old1, const double time1, const double old2, const double time2)
  338. {
  339. double retValue;
  340. if (time1 == time2 || old1 == old2)
  341. {
  342. retValue = old1;
  343. }
  344. else
  345. {
  346. retValue = old2 + ((time - time2)/(time1 - time2)) * (old1-old2);
  347. }
  348. return retValue;
  349. }