2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2011 - DIGITEO - Cedric DELAMARRE
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
12 /*--------------------------------------------------------------------------*/
14 #include "differential_equations_gw.hxx"
15 #include "function.hxx"
19 #include "callable.hxx"
20 #include "differentialequationfunctions.hxx"
21 #include "runvisitor.hxx"
25 #include "sci_malloc.h"
26 #include "localization.h"
28 #include "scifunctions.h"
29 #include "elem_common.h"
30 #include "checkodeerror.h"
32 #include "common_structure.h"
34 /*--------------------------------------------------------------------------*/
36 types::Function::ReturnValue sci_impl(types::typed_list &in, int _iRetCount, types::typed_list &out)
39 types::String* pStrType = NULL;
40 const wchar_t * wcsType = L"lsoda";
41 int meth = 2;// default methode is stiff
44 types::Double* pDblY0 = NULL;
45 double* pdYData = NULL; // contain y0 following by all args data in list case.
46 int sizeOfpdYData = 0;
49 types::Double* pDblYdot0 = NULL;
50 types::Double* pDblT0 = NULL;
51 types::Double* pDblT = NULL;
52 types::Double* pDblRtol = NULL;
53 types::Double* pDblAtol = NULL;
54 types::Double* pDblW = NULL;
55 types::Double* pDblIw = NULL;
58 types::Double* pDblYOut = NULL;
60 // Indicate if the function is given.
61 bool bFuncF = false; // res
62 bool bFuncJac = false; // jac
63 bool bFuncG = false; // adda
65 int iPos = 0; // Position in types::typed_list in
66 int maxord = 5; // maxord = 12 (if meth = 1) or 5 (if meth = 2)
69 int* YSize = NULL; // YSize(1) = size of y0,
70 // YSize(n) = size of Args(n) in list case.
72 C2F(eh0001).mesflg = 1; // flag to control printing of error messages in lapack routine.
73 // 1 means print, 0 means no printing.
74 C2F(eh0001).lunit = 6; // 6 = stdout
76 int one = 1; // use in dcopy
78 // *** check the minimal number of input args. ***
79 if (in.size() < 6 || in.size() > 12)
81 Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "impl", 6, 12);
82 return types::Function::Error;
85 // *** check number of output args ***
86 if (_iRetCount > 3 || _iRetCount == 2)
88 Scierror(78, _("%s: Wrong number of output argument(s): %d or %d expected.\n"), "impl", 1, 3);
89 return types::Function::Error;
92 // *** Get the methode. ***
93 if (in[0]->isString())
95 pStrType = in[0]->getAs<types::String>();
96 wcsType = pStrType->get(0);
102 if (wcscmp(wcsType, L"adams") == 0)
107 else if (wcscmp(wcsType, L"stiff") == 0)
113 Scierror(999, _("%s: Wrong value for input argument #%d: It must be one of the following strings: adams or stiff.\n"), "impl", 1);
114 return types::Function::Error;
118 // *** check type of input args and get it. ***
120 if (in[iPos]->isDouble() == false)
122 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix expected.\n"), "impl", iPos + 1);
123 return types::Function::Error;
126 pDblY0 = in[iPos]->getAs<types::Double>();
128 if (pDblY0->isComplex())
130 Scierror(999, _("%s: Wrong type for input argument #%d: A real matrix expected.\n"), "impl", iPos + 1);
131 return types::Function::Error;
134 if (pDblY0->getCols() != 1 && pDblY0->getRows() != 1)
136 Scierror(999, _("%s: Wrong type for input argument #%d: A real vector expected.\n"), "impl", iPos + 1);
137 return types::Function::Error;
142 if (in[iPos]->isDouble() == false)
144 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix expected.\n"), "impl", iPos + 1);
145 return types::Function::Error;
148 pDblYdot0 = in[iPos]->getAs<types::Double>();
150 if (pDblYdot0->isComplex())
152 Scierror(999, _("%s: Wrong type for input argument #%d: A real matrix expected.\n"), "impl", iPos + 1);
153 return types::Function::Error;
156 if (pDblYdot0->getCols() != 1 && pDblYdot0->getRows() != 1)
158 Scierror(999, _("%s: Wrong type for input argument #%d: A real vector expected.\n"), "impl", iPos + 1);
159 return types::Function::Error;
164 if (in[iPos]->isDouble() == false)
166 Scierror(999, _("%s: Wrong type for input argument #%d: A scalar expected.\n"), "impl", iPos + 1);
167 return types::Function::Error;
170 pDblT0 = in[iPos]->getAs<types::Double>();
172 if (pDblT0->isScalar() == false)
174 Scierror(999, _("%s: Wrong size for input argument #%d: A scalar expected.\n"), "impl", iPos + 1);
175 return types::Function::Error;
180 if (in[iPos]->isDouble() == false)
182 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix expected.\n"), "impl", iPos + 1);
183 return types::Function::Error;
186 pDblT = in[iPos]->getAs<types::Double>();
189 DifferentialEquationFunctions* deFunctionsManager = new DifferentialEquationFunctions(L"impl");
190 DifferentialEquation::addDifferentialEquationFunctions(deFunctionsManager);
192 YSize = (int*)malloc(sizeOfYSize * sizeof(int));
193 *YSize = pDblY0->getSize();
194 pdYData = (double*)malloc(pDblY0->getSize() * sizeof(double));
195 C2F(dcopy)(YSize, pDblY0->get(), &one, pdYData, &one);
197 for (iPos++; iPos < in.size(); iPos++)
199 if (in[iPos]->isDouble())
201 if (pDblAtol == NULL && bFuncF == false)
203 pDblAtol = in[iPos]->getAs<types::Double>();
204 if (pDblAtol->getSize() != pDblY0->getSize() && pDblAtol->isScalar() == false)
206 Scierror(267, _("%s: Arg %d and arg %d must have equal dimensions.\n"), "impl", pStrType ? 2 : 1, iPos + 1);
207 DifferentialEquation::removeDifferentialEquationFunctions();
210 return types::Function::Error;
213 else if (pDblRtol == NULL && bFuncF == false)
215 pDblRtol = in[iPos]->getAs<types::Double>();
216 if (pDblRtol->getSize() != pDblY0->getSize() && pDblRtol->isScalar() == false)
218 Scierror(267, _("%s: Arg %d and arg %d must have equal dimensions.\n"), "impl", pStrType ? 2 : 1, iPos + 1);
219 DifferentialEquation::removeDifferentialEquationFunctions();
222 return types::Function::Error;
225 else if (pDblW == NULL && bFuncG == true)
227 if (in.size() == iPos + 2)
229 if (in[iPos + 1]->isDouble() == false)
231 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix expected.\n"), "impl", iPos + 2);
232 DifferentialEquation::removeDifferentialEquationFunctions();
235 return types::Function::Error;
238 pDblW = in[iPos]->getAs<types::Double>();
239 pDblIw = in[iPos + 1]->getAs<types::Double>();
244 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "impl", iPos + 2);
245 DifferentialEquation::removeDifferentialEquationFunctions();
248 return types::Function::Error;
253 Scierror(999, _("%s: Wrong type for input argument #%d: A function expected.\n"), "impl", iPos + 1);
254 DifferentialEquation::removeDifferentialEquationFunctions();
257 return types::Function::Error;
260 else if (in[iPos]->isCallable())
262 types::Callable* pCall = in[iPos]->getAs<types::Callable>();
265 deFunctionsManager->setFFunction(pCall);
268 else if (bFuncG == false)
270 deFunctionsManager->setGFunction(pCall);
273 else if (bFuncJac == false)
275 deFunctionsManager->setJacFunction(pCall);
280 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix expected.\n"), "impl", iPos + 1);
281 DifferentialEquation::removeDifferentialEquationFunctions();
284 return types::Function::Error;
287 else if (in[iPos]->isString())
289 types::String* pStr = in[iPos]->getAs<types::String>();
294 bOK = deFunctionsManager->setFFunction(pStr);
297 else if (bFuncG == false)
299 bOK = deFunctionsManager->setGFunction(pStr);
302 else if (bFuncJac == false)
304 bOK = deFunctionsManager->setJacFunction(pStr);
309 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix expected.\n"), "impl", iPos + 1);
310 DifferentialEquation::removeDifferentialEquationFunctions();
313 return types::Function::Error;
318 char* pst = wide_string_to_UTF8(pStr->get(0));
319 Scierror(50, _("%s: Subroutine not found: %s\n"), "impl", pst);
321 DifferentialEquation::removeDifferentialEquationFunctions();
324 return types::Function::Error;
327 else if (in[iPos]->isList())
329 types::List* pList = in[iPos]->getAs<types::List>();
331 if (pList->getSize() == 0)
333 Scierror(50, _("%s: Argument #%d: Subroutine not found in list: %s\n"), "impl", iPos + 1, "(string empty)");
334 DifferentialEquation::removeDifferentialEquationFunctions();
337 return types::Function::Error;
340 if (bFuncF && bFuncG && bFuncJac)
342 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix expected.\n"), "impl", iPos + 1);
343 DifferentialEquation::removeDifferentialEquationFunctions();
346 return types::Function::Error;
349 if (pList->get(0)->isString())
351 types::String* pStr = pList->get(0)->getAs<types::String>();
357 bOK = deFunctionsManager->setFFunction(pStr);
358 sizeOfpdYData = *YSize;
360 else if (bFuncG == false)
363 bOK = deFunctionsManager->setGFunction(pStr);
364 if (sizeOfpdYData == 0)
366 sizeOfpdYData = *YSize;
369 else if (bFuncJac == false)
372 bOK = deFunctionsManager->setJacFunction(pStr);
373 if (sizeOfpdYData == 0)
375 sizeOfpdYData = *YSize;
381 char* pst = wide_string_to_UTF8(pStr->get(0));
382 Scierror(50, _("%s: Argument #%d: Subroutine not found in list: %s\n"), "impl", iPos + 1, pst);
384 DifferentialEquation::removeDifferentialEquationFunctions();
387 return types::Function::Error;
390 int* sizeTemp = YSize;
391 int totalSize = sizeOfpdYData;
393 YSize = (int*)malloc((sizeOfYSize + pList->getSize() - 1) * sizeof(int));
394 memcpy(YSize, sizeTemp, sizeOfYSize * sizeof(int));
396 std::vector<types::Double*> vpDbl;
397 for (int iter = 0; iter < pList->getSize() - 1; iter++)
399 if (pList->get(iter + 1)->isDouble() == false)
401 Scierror(999, _("%s: Wrong type for input argument #%d: Argument %d in the list must be a matrix.\n"), "impl", iPos + 1, iter + 1);
402 DifferentialEquation::removeDifferentialEquationFunctions();
405 return types::Function::Error;
408 vpDbl.push_back(pList->get(iter + 1)->getAs<types::Double>());
409 YSize[sizeOfYSize + iter] = vpDbl[iter]->getSize();
410 totalSize += YSize[sizeOfYSize + iter];
413 double* pdYDataTemp = pdYData;
414 pdYData = (double*)malloc(totalSize * sizeof(double));
415 C2F(dcopy)(&sizeOfpdYData, pdYDataTemp, &one, pdYData, &one);
417 int position = sizeOfpdYData;
418 for (int iter = 0; iter < pList->getSize() - 1; iter++)
420 C2F(dcopy)(&YSize[sizeOfYSize + iter], vpDbl[iter]->get(), &one, &pdYData[position], &one);
421 position += vpDbl[iter]->getSize();
424 sizeOfpdYData = totalSize;
425 sizeOfYSize += pList->getSize() - 1;
429 else if (pList->get(0)->isCallable())
434 deFunctionsManager->setFFunction(pList->get(0)->getAs<types::Callable>());
435 for (int iter = 1; iter < pList->getSize(); iter++)
437 deFunctionsManager->setFArgs(pList->get(iter)->getAs<types::InternalType>());
440 else if (bFuncG == false)
443 deFunctionsManager->setGFunction(pList->get(0)->getAs<types::Callable>());
444 for (int iter = 1; iter < pList->getSize(); iter++)
446 deFunctionsManager->setGArgs(pList->get(iter)->getAs<types::InternalType>());
449 else if (bFuncJac == false)
452 deFunctionsManager->setJacFunction(pList->get(0)->getAs<types::Callable>());
453 for (int iter = 1; iter < pList->getSize(); iter++)
455 deFunctionsManager->setJacArgs(pList->get(iter)->getAs<types::InternalType>());
461 Scierror(999, _("%s: Wrong type for input argument #%d: The first argument in the list must be a string or a function.\n"), "impl", iPos + 1);
462 DifferentialEquation::removeDifferentialEquationFunctions();
465 return types::Function::Error;
470 Scierror(999, _("%s: Wrong type for input argument #%d: A matrix or a function expected.\n"), "impl", iPos + 1);
471 DifferentialEquation::removeDifferentialEquationFunctions();
474 return types::Function::Error;
480 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "impl", in.size() + 1);
481 DifferentialEquation::removeDifferentialEquationFunctions();
484 return types::Function::Error;
489 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "impl", in.size() + 1);
490 DifferentialEquation::removeDifferentialEquationFunctions();
493 return types::Function::Error;
496 // *** Initialization. ***
497 double t0 = pDblT0->get(0);
502 int jt = bFuncJac ? 1 : 2;
503 int jacType = 10 * meth + jt;
505 pDblYOut = new types::Double(pDblY0->getRows(), pDblT->getSize());
508 double* rwork = NULL;
513 // contain ls0001, lsa001 and eh0001 structures
514 double* dStructTab = NULL;
515 int* iStructTab = NULL;
516 int dStructTabSize = 219; // number of double in ls0001
517 int iStructTabSize = 41; // number of int in ls0001 (39) + eh0001 (2)
519 int rwSize = 0; // rwSize = dStructTab + rworkSize
520 int iwSize = 0; // iwSize = iStructTab + iworkSize
522 // structures used by lsoda and lsode
523 double* ls0001d = &(C2F(ls0001).tret);
524 int* ls0001i = &(C2F(ls0001).illin);
525 int* eh0001i = &(C2F(eh0001).mesflg);
527 //compute itol and set the tolerances rtol and atol.
533 if (pDblRtol->isScalar())
535 rtol = (double*)malloc(sizeof(double));
536 *rtol = pDblRtol->get(0);
540 rtol = pDblRtol->get();
546 rtol = (double*)malloc(sizeof(double));
552 if (pDblAtol->isScalar())
554 atol = (double*)malloc(sizeof(double));
555 *atol = pDblAtol->get(0);
559 atol = pDblAtol->get();
565 atol = (double*)malloc(sizeof(double));
569 // Compute rwork, iwork size.
573 if (pDblW) // structure ls0001 have been restored.
575 nyh = C2F(ls0001).nyh;
578 rworkSize = 20 + nyh * (maxord + 1) + 3 * *YSize + *YSize * *YSize + 2;
579 iworkSize = 20 + *YSize;
581 rwSize = rworkSize + dStructTabSize;
582 iwSize = iworkSize + iStructTabSize;
584 rwork = (double*)malloc(rworkSize * sizeof(double));
585 iwork = (int*)malloc(iworkSize * sizeof(int));
589 if (pDblW->getSize() != rwSize || pDblIw->getSize() != iwSize)
591 Scierror(9999, _("%s: Wrong size for w and iw: w = %d and iw = %d expected.\n"), "impl", rwSize, iwSize);
592 DifferentialEquation::removeDifferentialEquationFunctions();
597 if (itol == 1 || itol == 3)
605 return types::Function::Error;
608 istate = 2; // 1 means this is the first call | 2 means this is not the first call
610 // restore rwork from pDblW
611 C2F(dcopy)(&rworkSize, pDblW->get(), &one, rwork, &one);
613 // restore iwork from pDblIw
614 iStructTab = (int*)malloc(iStructTabSize * sizeof(int));
615 for (int i = 0; i < iworkSize; i++)
617 iwork[i] = (int)pDblIw->get(i);
620 //restore ls0001d from pDblW
621 C2F(dcopy)(&dStructTabSize, pDblW->get() + rworkSize, &one, ls0001d, &one);
623 //restore ls0001i from pDblIw
624 for (int i = 0; i < iStructTabSize; i++)
626 iStructTab[i] = (int)pDblIw->get(i + iworkSize);
628 memcpy(ls0001i, iStructTab, 39 * sizeof(int));
631 // *** Perform operation. ***
633 for (int i = 0; i < pDblT->getSize(); i++)
635 double t = pDblT->get(i);
638 C2F(lsodi)(impl_f, impl_g, impl_jac, YSize, pdYData, pDblYdot0->get(), &t0, &t, &itol, rtol, atol, &itask, &istate, &iopt, rwork, &rworkSize, iwork, &iworkSize, &jacType);
643 sciprint(_("The user-supplied subroutine res signalled lsodi to halt the integration and return (ires=2). Execution of the external function has failed.\n"));
645 Scierror(999, _("%s: %s exit with state %d.\n"), "impl", "lsodi", istate);
649 err = checkOdeError(meth, istate);
652 Scierror(999, _("%s: %s exit with state %d.\n"), "impl", "lsodi", istate);
656 catch (ast::ScilabError &e)
658 char* pstrMsg = wide_string_to_UTF8(e.GetErrorMessage().c_str());
659 sciprint(_("%s: exception caught in '%s' subroutine.\n"), "impl", "lsodi");
660 Scierror(999, pstrMsg);
667 DifferentialEquation::removeDifferentialEquationFunctions();
676 if (itol == 1 || itol == 3)
684 return types::Function::Error;
687 for (int j = 0; j < *YSize; j++)
689 pDblYOut->set(i * (*YSize) + j, pdYData[j]);
693 if (_iRetCount > 2) //save ls0001 and eh0001 following pDblW and pDblIw.
697 if (iStructTab == NULL)
699 iStructTab = (int*)malloc(iStructTabSize * sizeof(int));
702 if (dStructTab == NULL)
704 dStructTab = (double*)malloc(dStructTabSize * sizeof(double));
708 C2F(dcopy)(&dSize, ls0001d, &one, dStructTab, &one);
709 memcpy(iStructTab, ls0001i, 39 * sizeof(int));
712 memcpy(&iStructTab[39], eh0001i, 2 * sizeof(int));
715 // *** Return result in Scilab. ***
716 out.push_back(pDblYOut);
720 types::Double* pDblWOut = new types::Double(1, rwSize);
721 C2F(dcopy)(&rworkSize, rwork, &one, pDblWOut->get(), &one);
722 C2F(dcopy)(&dStructTabSize, dStructTab, &one, pDblWOut->get() + rworkSize, &one);
724 types::Double* pDblIwOut = new types::Double(1, iwSize);
725 for (int i = 0; i < iworkSize; i++)
727 pDblIwOut->set(i, (double)iwork[i]);
730 for (int i = 0; i < iStructTabSize; i++)
732 pDblIwOut->set(iworkSize + i, (double)iStructTab[i]);
735 out.push_back(pDblWOut);
736 out.push_back(pDblIwOut);
740 if (itol == 1 || itol == 3) // atol is scalar
745 if (itol < 3) // rtol is scalar
765 DifferentialEquation::removeDifferentialEquationFunctions();
767 return types::Function::OK;