odepkg/0000755000176000010400000000000012111623641013203 5ustar marcoAdministratorsodepkg/COPYING0000644000176000010400000004307710751613601014254 0ustar marcoAdministrators GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. odepkg/DESCRIPTION0000644000176000010400000000054212111613217014710 0ustar marcoAdministratorsName: OdePkg Version: 0.8.4 Date: 2013-02-22 Author: Thomas Treichl Maintainer: Thomas Treichl Title: OdePkg Description: A package for solving ordinary differential equations and more. Categories: Differential Equations Depends: octave (>= 3.2.0) License: GPLv2+ Url: http://octave.sf.net odepkg/doc/0000755000176000010400000000000012111634317013752 5ustar marcoAdministratorsodepkg/doc/dldfunref.texi0000644000176000010400000004527310766455460016647 0ustar marcoAdministrators@deftypefn {Command} {[@var{}] =} odebda (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} odebda (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odebda (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff or stiff ordinary differential equations (ODEs) and non--stiff or stiff differential algebraic equations (DAEs). This function file is a wrapper file that uses Jeff Cash's Fortran solver @file{mebdfdae.f}. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, @example function y = odepkg_equations_lorenz (t, x) y = [10 * (x(2) - x(1)); x(1) * (28 - x(3)); x(1) * x(2) - 8/3 * x(3)]; endfunction vopt = odeset ("InitialStep", 1e-3, "MaxStep", 1e-1, \\ "OutputFcn", @@odephas3, "Refine", 5); odebda (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt); @end example @end deftypefn @deftypefn {Command} {[@var{}] =} odebdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} odebdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odebdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}]) This function file can be used to solve a set of non--stiff and stiff implicit differential equations (IDEs). This function file is a wrapper file that uses Jeff Cash's Fortran solver @file{mebdfi.f}. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of IDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{y0} is a double vector that defines the initial values of the states, @var{dy0} is a double vector that defines the initial values of the derivatives, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of IDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, @example function res = odepkg_equations_ilorenz (t, y, yd) res = [10 * (y(2) - y(1)) - yd(1); y(1) * (28 - y(3)) - yd(2); y(1) * y(2) - 8/3 * y(3) - yd(3)]; endfunction vopt = odeset ("InitialStep", 1e-3, "MaxStep", 1e-1, \\ "OutputFcn", @@odephas3, "Refine", 5); odebdi (@@odepkg_equations_ilorenz, [0, 25], [3 15 1], \\ [120 81 42.333333], vopt); @end example @end deftypefn @deftypefn {Command} {[@var{}] =} odekdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} odekdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odekdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}]) This function file can be used to solve a set of non--stiff or stiff implicit differential equations (IDEs). This function file is a wrapper file that uses the direct method (not the Krylov method) of Petzold's, Brown's, Hindmarsh's and Ulrich's Fortran solver @file{ddaskr.f}. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of IDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{y0} is a double vector that defines the initial values of the states, @var{dy0} is a double vector that defines the initial values of the derivatives, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of IDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, @example function res = odepkg_equations_ilorenz (t, y, yd) res = [10 * (y(2) - y(1)) - yd(1); y(1) * (28 - y(3)) - yd(2); y(1) * y(2) - 8/3 * y(3) - yd(3)]; endfunction vopt = odeset ("InitialStep", 1e-3, "MaxStep", 1e-1, \\ "OutputFcn", @@odephas3, "Refine", 5); odekdi (@@odepkg_equations_ilorenz, [0, 25], [3 15 1], \\ [120 81 42.333333], vopt); @end example @end deftypefn @deftypefn {Command} {[@var{}] =} ode2r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode2r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode2r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff or stiff ordinary differential equations (ODEs) and non--stiff or stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{radau.f}. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, @example function y = odepkg_equations_lorenz (t, x) y = [10 * (x(2) - x(1)); x(1) * (28 - x(3)); x(1) * x(2) - 8/3 * x(3)]; endfunction vopt = odeset ("InitialStep", 1e-3, "MaxStep", 1e-1, \\ "OutputFcn", @@odephas3, "Refine", 5); ode2r (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt); @end example @end deftypefn @deftypefn {Command} {[@var{}] =} ode5r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode5r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode5r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff or stiff ordinary differential equations (ODEs) and non--stiff or stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{radau5.f}. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, @example function y = odepkg_equations_lorenz (t, x) y = [10 * (x(2) - x(1)); x(1) * (28 - x(3)); x(1) * x(2) - 8/3 * x(3)]; endfunction vopt = odeset ("InitialStep", 1e-3, "MaxStep", 1e-1, \\ "OutputFcn", @@odephas3, "Refine", 5); ode5r (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{}] =} oders (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} oders (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} oders (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff or stiff ordinary differential equations (ODEs) and non--stiff or stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{rodas.f}. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, @example function y = odepkg_equations_lorenz (t, x) y = [10 * (x(2) - x(1)); x(1) * (28 - x(3)); x(1) * x(2) - 8/3 * x(3)]; endfunction vopt = odeset ("InitialStep", 1e-3, "MaxStep", 1e-1, \\ "OutputFcn", @@odephas3, "Refine", 5); oders (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt); @end example @end deftypefn @deftypefn {Command} {[@var{}] =} odesx (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} odesx (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odesx (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of stiff or non--stiff ordinary differential equations (ODEs) and non--stiff or stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{seulex.f}. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, @example function y = odepkg_equations_lorenz (t, x) y = [10 * (x(2) - x(1)); x(1) * (28 - x(3)); x(1) * x(2) - 8/3 * x(3)]; endfunction vopt = odeset ("InitialStep", 1e-3, "MaxStep", 1e-1, \\ "OutputFcn", @@odephas3, "Refine", 5); odesx (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt); @end example @end deftypefn odepkg/doc/Makefile0000644000176000010400000000450511030757403015417 0ustar marcoAdministrators# Filename: Makefile # Description: Makefile for the doc directory of the OdePkg # ChangeLog: 20070222, this Makefile was originally be created # from the Makefile of the comm package. Modifications have # been done to create the documentation of the OdePkg. sinclude ../../../Makeconf # Fill in the variables as it makes testing the package manager easier ifeq ($(MKDOC),) MKDOC = ../../../admin/mkdoc MKTEXI = ../../../admin/mktexi MAKEINFO = makeinfo --no-split --document-language=en_us TEXI2DVI = texi2dvi --clean DVIPS = dvips LN_S = ln -s endif INFODOC = odepkg.info PSDOC = $(patsubst %.info, %.ps, $(INFODOC)) PDFDOC = $(patsubst %.info, %.pdf, $(INFODOC)) HTMLDOC = $(patsubst %.info, %.html, $(INFODOC)) TEXIDOC = $(patsubst %.info, %.txi, $(INFODOC)) DOCS = $(INFODOC) $(PDFDOC) DOCSTRINGS = DOCSTRINGS INDEX = ../INDEX TMPDELETES = *.log *.dvi $(DOCSTRINGS) $(TEXIDOC) *~ DELETES = $(TMPDELETES) *.ps *.pdf *.info $(DOCS) *.html odepkg/ html/ all : $(PDFDOC) $(HTMLDOC) ../inst/doc.info .PHONY : all ../inst/doc.info : $(INFODOC) cp -f $(INFODOC) ../inst/doc.info ifeq (,$(TEXI2PDF)) %.pdf : %.dvi @if test "x$(TEXI2DVI)" != "x" && test "x$(DVIPDF)" != "x"; then \ echo "Making pdf $@"; \ $(DVIPDF) $< ; \ fi %.dvi : %.texi @if test "x$(TEXI2DVI)" != "x"; then \ echo "Making dvi $@"; \ TEXINPUTS="./:$../../..:$(TEXINPUTS):"; \ export TEXINPUTS; \ $(TEXI2DVI) $< ; \ fi %.ps : %.dvi @if test "x$(TEXI2DVI)" != "x" && test "x$(DVIPS)" != "x"; then \ echo "Making postscript $@"; \ $(DVIPS) -o $@ $< ; \ fi else %.pdf : %.texi @if test "x$(TEXI2PDF)" != "x"; then \ echo "Making pdf $@"; \ TEXINPUTS="./:../../..:$(TEXINPUTS):"; \ export TEXINPUTS; \ $(TEXI2PDF) $< ; \ fi endif %.info : %.texi @if test "x$(MAKEINFO)" != "x"; then \ echo "Making info $@"; \ $(MAKEINFO) -I./ -I../../../ $< ; \ fi %.html : %.texi @if test "x$(MAKEINFO)" != "x"; then \ echo "Making html $@"; \ $(MAKEINFO) --html -I./ -I../../../ $< ; \ fi %.texi : %.txi $(RM) -f $(DOCSTRINGS); \ $(MKDOC) ../ > $(DOCSTRINGS); \ $(MKTEXI) $< $(DOCSTRINGS) $(INDEX) > $@ ; \ $(RM) -f $(DOCSTRINGS); clean : @echo "Cleaning..."; \ $(RM) -fr $(DELETES) ../inst/doc.info; .PHONY : clean realclean : clean .PHONY : realclean distclean : clean .PHONY : distclean dist : all .PHONY : dist odepkg/doc/mfunref.texi0000644000176000010400000014171111714561373016325 0ustar marcoAdministrators@deftypefn {Function File} {[@var{}] =} ode23 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode23 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode23 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (2,3). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, solve an anonymous implementation of the Van der Pol equation @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ "NormControl", "on", "OutputFcn", @@odeplot); ode23 (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{}] =} ode23d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode23d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode23d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (2,3). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. In other words, this function will solve a problem of the form @example dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) y(slot(1)) = init y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} @end example If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example: @itemize @minus @item the following code solves an anonymous implementation of a chaotic behavior @example fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; vopt = odeset ("NormControl", "on", "RelTol", 1e-3); vsol = ode23d (fcao, [0, 100], 0.5, 2, 0.5, vopt); vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); plot (vsol.y, vlag); legend ("fcao (t,y,z)"); @end example @item to solve the following problem with two delayed state variables @example d y1(t)/dt = -y1(t) d y2(t)/dt = -y2(t) + y1(t-5) d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) @end example one might do the following @example function f = fun (t, y, yd) f(1) = -y(1); %% y1' = -y1(t) f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) endfunction T = [0,20] res = ode23d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); @end example @end itemize @end deftypefn @deftypefn {Function File} {[@var{}] =} ode45 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode45 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode45 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (4,5). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, solve an anonymous implementation of the Van der Pol equation @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ "NormControl", "on", "OutputFcn", @@odeplot); ode45 (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{}] =} ode45d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode45d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode45d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (4,5). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. In other words, this function will solve a problem of the form @example dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) y(slot(1)) = init y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} @end example If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example: @itemize @minus @item the following code solves an anonymous implementation of a chaotic behavior @example fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; vopt = odeset ("NormControl", "on", "RelTol", 1e-3); vsol = ode45d (fcao, [0, 100], 0.5, 2, 0.5, vopt); vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); plot (vsol.y, vlag); legend ("fcao (t,y,z)"); @end example @item to solve the following problem with two delayed state variables @example d y1(t)/dt = -y1(t) d y2(t)/dt = -y2(t) + y1(t-5) d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) @end example one might do the following @example function f = fun (t, y, yd) f(1) = -y(1); %% y1' = -y1(t) f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) endfunction T = [0,20] res = ode45d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); @end example @end itemize @end deftypefn @deftypefn {Function File} {[@var{}] =} ode54 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode54 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode54 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (5,4). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, solve an anonymous implementation of the Van der Pol equation @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ "NormControl", "on", "OutputFcn", @@odeplot); ode54 (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{}] =} ode54d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode54d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode54d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (2,3). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. In other words, this function will solve a problem of the form @example dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) y(slot(1)) = init y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} @end example If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example: @itemize @minus @item the following code solves an anonymous implementation of a chaotic behavior @example fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; vopt = odeset ("NormControl", "on", "RelTol", 1e-3); vsol = ode54d (fcao, [0, 100], 0.5, 2, 0.5, vopt); vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); plot (vsol.y, vlag); legend ("fcao (t,y,z)"); @end example @item to solve the following problem with two delayed state variables @example d y1(t)/dt = -y1(t) d y2(t)/dt = -y2(t) + y1(t-5) d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) @end example one might do the following @example function f = fun (t, y, yd) f(1) = -y(1); %% y1' = -y1(t) f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) endfunction T = [0,20] res = ode54d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); @end example @end itemize @end deftypefn @deftypefn {Function File} {[@var{}] =} ode78 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode78 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode78 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (7,8). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, solve an anonymous implementation of the Van der Pol equation @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ "NormControl", "on", "OutputFcn", @@odeplot); ode78 (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{}] =} ode78d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} ode78d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode78d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (7,8). If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. In other words, this function will solve a problem of the form @example dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) y(slot(1)) = init y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} @end example If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example: @itemize @minus @item the following code solves an anonymous implementation of a chaotic behavior @example fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; vopt = odeset ("NormControl", "on", "RelTol", 1e-3); vsol = ode78d (fcao, [0, 100], 0.5, 2, 0.5, vopt); vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); plot (vsol.y, vlag); legend ("fcao (t,y,z)"); @end example @item to solve the following problem with two delayed state variables @example d y1(t)/dt = -y1(t) d y2(t)/dt = -y2(t) + y1(t-5) d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) @end example one might do the following @example function f = fun (t, y, yd) f(1) = -y(1); %% y1' = -y1(t) f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) endfunction T = [0,20] res = ode78d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); @end example @end itemize @end deftypefn @deftypefn {Function File} {[@var{}] =} odebwe (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{sol}] =} odebwe (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odebwe (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) This function file can be used to solve a set of stiff ordinary differential equations (stiff ODEs) or stiff differential algebraic equations (stiff DAEs) with the Backward Euler method. If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. For example, solve an anonymous implementation of the Van der Pol equation @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vjac = @@(vt,vy) [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ "NormControl", "on", "OutputFcn", @@odeplot, \ "Jacobian",vjac); odebwe (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{}] =} odeexamples (@var{}) Open the differential equations examples menu and allow the user to select a submenu of ODE, DAE, IDE or DDE examples. @end deftypefn @deftypefn {Function File} {[@var{value}] =} odeget (@var{odestruct}, @var{option}, [@var{default}]) @deftypefnx {Command} {[@var{values}] =} odeget (@var{odestruct}, @{@var{opt1}, @var{opt2}, @dots{}@}, [@{@var{def1}, @var{def2}, @dots{}@}]) If this function is called with two input arguments and the first input argument @var{odestruct} is of type structure array and the second input argument @var{option} is of type string then return the option value @var{value} that is specified by the option name @var{option} in the OdePkg option structure @var{odestruct}. Optionally if this function is called with a third input argument then return the default value @var{default} if @var{option} is not set in the structure @var{odestruct}. If this function is called with two input arguments and the first input argument @var{odestruct} is of type structure array and the second input argument @var{option} is of type cell array of strings then return the option values @var{values} that are specified by the option names @var{opt1}, @var{opt2}, @dots{} in the OdePkg option structure @var{odestruct}. Optionally if this function is called with a third input argument of type cell array then return the default value @var{def1} if @var{opt1} is not set in the structure @var{odestruct}, @var{def2} if @var{opt2} is not set in the structure @var{odestruct}, @dots{} Run examples with the command @example demo odeget @end example @end deftypefn @deftypefn {Function File} {[@var{ret}] =} odephas2 (@var{t}, @var{y}, @var{flag}) Open a new figure window and plot the first result from the variable @var{y} that is of type double column vector over the second result from the variable @var{y} while solving. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is @table @option @item @code{"init"} then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, @item @code{""} then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', @item @code{"done"} then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. @end table This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. For example, solve an anonymous implementation of the "Van der Pol" equation and display the results while solving in a 2D plane @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vopt = odeset ('OutputFcn', @@odephas2, 'RelTol', 1e-6); vsol = ode45 (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{ret}] =} odephas3 (@var{t}, @var{y}, @var{flag}) Open a new figure window and plot the first result from the variable @var{y} that is of type double column vector over the second and the third result from the variable @var{y} while solving. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is @table @option @item @code{"init"} then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, @item @code{""} then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', @item @code{"done"} then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. @end table This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. For example, solve the "Lorenz attractor" and display the results while solving in a 3D plane @example function vyd = florenz (vt, vx) vyd = [10 * (vx(2) - vx(1)); vx(1) * (28 - vx(3)); vx(1) * vx(2) - 8/3 * vx(3)]; endfunction vopt = odeset ('OutputFcn', @@odephas3); vsol = ode23 (@@florenz, [0:0.01:7.5], [3 15 1], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{}] =} odepkg () OdePkg is part of the GNU Octave Repository (the Octave--Forge project). The package includes commands for setting up various options, output functions etc. before solving a set of differential equations with the solver functions that are also included. At this time OdePkg is under development with the main target to make a package that is mostly compatible to proprietary solver products. If this function is called without any input argument then open the OdePkg tutorial in the Octave window. The tutorial can also be opened with the following command @example doc odepkg @end example @end deftypefn @deftypefn {Function File} {[@var{sol}] =} odepkg_event_handle (@var{@@fun}, @var{time}, @var{y}, @var{flag}, [@var{par1}, @var{par2}, @dots{}]) Return the solution of the event function that is specified as the first input argument @var{@@fun} in form of a function handle. The second input argument @var{time} is of type double scalar and specifies the time of the event evaluation, the third input argument @var{y} either is of type double column vector (for ODEs and DAEs) and specifies the solutions or is of type cell array (for IDEs and DDEs) and specifies the derivatives or the history values, the third input argument @var{flag} is of type string and can be of the form @table @option @item @code{"init"} then initialize internal persistent variables of the function @command{odepkg_event_handle} and return an empty cell array of size 4, @item @code{"calc"} then do the evaluation of the event function and return the solution @var{sol} as type cell array of size 4, @item @code{"done"} then cleanup internal variables of the function @command{odepkg_event_handle} and return an empty cell array of size 4. @end table Optionally if further input arguments @var{par1}, @var{par2}, @dots{} of any type are given then pass these parameters through @command{odepkg_event_handle} to the event function. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. @end deftypefn @deftypefn {Function File} {[@var{}] =} odepkg_examples_dae (@var{}) Open the DAE examples menu and allow the user to select a demo that will be evaluated. @end deftypefn @deftypefn {Function File} {[@var{}] =} odepkg_examples_dde (@var{}) Open the DDE examples menu and allow the user to select a demo that will be evaluated. @end deftypefn @deftypefn {Function File} {[@var{}] =} odepkg_examples_ide (@var{}) Open the IDE examples menu and allow the user to select a demo that will be evaluated. @end deftypefn @deftypefn {Function File} {[@var{}] =} odepkg_examples_ode (@var{}) Open the ODE examples menu and allow the user to select a demo that will be evaluated. @end deftypefn @deftypefn {Function File} {[@var{newstruct}] =} odepkg_structure_check (@var{oldstruct}, [@var{"solver"}]) If this function is called with one input argument of type structure array then check the field names and the field values of the OdePkg structure @var{oldstruct} and return the structure as @var{newstruct} if no error is found. Optionally if this function is called with a second input argument @var{"solver"} of type string taht specifies the name of a valid OdePkg solver then a higher level error detection is performed. The function does not modify any of the field names or field values but terminates with an error if an invalid option or value is found. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. Run examples with the command @example demo odepkg_structure_check @end example @end deftypefn @deftypefn {Function File} {[@var{mescd}] =} odepkg_testsuite_calcmescd (@var{solution}, @var{reference}, @var{abstol}, @var{reltol}) If this function is called with four input arguments of type double scalar or column vector then return a normalized value for the minimum number of correct digits @var{mescd} that is calculated from the solution at the end of an integration interval @var{solution} and a set of reference values @var{reference}. The input arguments @var{abstol} and @var{reltol} are used to calculate a reference solution that depends on the relative and absolute error tolerances. Run examples with the command @example demo odepkg_testsuite_calcmescd @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{scd}] =} odepkg_testsuite_calcscd (@var{solution}, @var{reference}, @var{abstol}, @var{reltol}) If this function is called with four input arguments of type double scalar or column vector then return a normalized value for the minimum number of correct digits @var{scd} that is calculated from the solution at the end of an integration interval @var{solution} and a set of reference values @var{reference}. The input arguments @var{abstol} and @var{reltol} are unused but present because of compatibility to the function @command{odepkg_testsuite_calcmescd}. Run examples with the command @example demo odepkg_testsuite_calcscd @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_chemakzo (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the chemical AKZO Nobel testsuite of differential algebraic equations after solving (DAE--test). Run examples with the command @example demo odepkg_testsuite_chemakzo @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_hires (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the HIRES testsuite of ordinary differential equations after solving (ODE--test). Run examples with the command @example demo odepkg_testsuite_hires @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_implakzo (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the chemical AKZO Nobel testsuite of implicit differential algebraic equations after solving (IDE--test). Run examples with the command @example demo odepkg_testsuite_implakzo @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_implrober (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the implicit form of the modified ROBERTSON testsuite of implicit differential algebraic equations after solving (IDE--test). Run examples with the command @example demo odepkg_testsuite_implrober @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_oregonator (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the OREGONATOR testsuite of ordinary differential equations after solving (ODE--test). Run examples with the command @example demo odepkg_testsuite_oregonator @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_pollution (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return the cell array @var{solution} with performance informations about the POLLUTION testsuite of ordinary differential equations after solving (ODE--test). Run examples with the command @example demo odepkg_testsuite_pollution @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_robertson (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the modified ROBERTSON testsuite of differential algebraic equations after solving (DAE--test). Run examples with the command @example demo odepkg_testsuite_robertson @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_transistor (@var{@@solver}, @var{reltol}) If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return the cell array @var{solution} with performance informations about the TRANSISTOR testsuite of differential algebraic equations after solving (DAE--test). Run examples with the command @example demo odepkg_testsuite_transistor @end example This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. @end deftypefn @deftypefn {Function File} {[@var{ret}] =} odeplot (@var{t}, @var{y}, @var{flag}) Open a new figure window and plot the results from the variable @var{y} of type column vector over time while solving. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is @table @option @item @code{"init"} then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, @item @code{""} then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', @item @code{"done"} then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. @end table This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. For example, solve an anonymous implementation of the "Van der Pol" equation and display the results while solving @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vopt = odeset ('OutputFcn', @@odeplot, 'RelTol', 1e-6); vsol = ode45 (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{ret}] =} odeprint (@var{t}, @var{y}, @var{flag}) Display the results of the set of differential equations in the Octave window while solving. The first column of the screen output shows the actual time stamp that is given with the input arguemtn @var{t}, the following columns show the results from the function evaluation that are given by the column vector @var{y}. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is @table @option @item @code{"init"} then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, @item @code{""} then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', @item @code{"done"} then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. @end table This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. For example, solve an anonymous implementation of the "Van der Pol" equation and print the results while solving @example fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; vopt = odeset ('OutputFcn', @@odeprint, 'RelTol', 1e-6); vsol = ode45 (fvdb, [0 20], [2 0], vopt); @end example @end deftypefn @deftypefn {Function File} {[@var{odestruct}] =} odeset () @deftypefnx {Command} {[@var{odestruct}] =} odeset (@var{"field1"}, @var{value1}, @var{"field2"}, @var{value2}, @dots{}) @deftypefnx {Command} {[@var{odestruct}] =} odeset (@var{oldstruct}, @var{"field1"}, @var{value1}, @var{"field2"}, @var{value2}, @dots{}) @deftypefnx {Command} {[@var{odestruct}] =} odeset (@var{oldstruct}, @var{newstruct}) If this function is called without an input argument then return a new OdePkg options structure array that contains all the necessary fields and sets the values of all fields to default values. If this function is called with string input arguments @var{"field1"}, @var{"field2"}, @dots{} identifying valid OdePkg options then return a new OdePkg options structure with all necessary fields and set the values of the fields @var{"field1"}, @var{"field2"}, @dots{} to the values @var{value1}, @var{value2}, @dots{} If this function is called with a first input argument @var{oldstruct} of type structure array then overwrite all values of the options @var{"field1"}, @var{"field2"}, @dots{} of the structure @var{oldstruct} with new values @var{value1}, @var{value2}, @dots{} and return the modified structure array. If this function is called with two input argumnets @var{oldstruct} and @var{newstruct} of type structure array then overwrite all values in the fields from the structure @var{oldstruct} with new values of the fields from the structure @var{newstruct}. Empty values of @var{newstruct} will not overwrite values in @var{oldstruct}. For a detailed explanation about valid fields and field values in an OdePkg structure aaray have a look at the @file{odepkg.pdf}, Section 'ODE/DAE/IDE/DDE options' or run the command @command{doc odepkg} to open the tutorial. Run examples with the command @example demo odeset @end example @end deftypefn odepkg/doc/odepkg.texi0000644000176000010400000017645211714561373016146 0ustar marcoAdministrators\input texinfo @c -*-texinfo-*- @c Copyright (c) 2006-2012, Thomas Treichl @c OdePkg - A package for solving ordinary differential equations and more @c For manually generating the documentation use @c LANGUAGE=en makeinfo --html --no-split odepkg.texi @c %*** Start of HEADER @setfilename odepkg.info @settitle OdePkg - A package for solving ordinary differential equations and more @afourpaper @set VERSION 0.8.2 @c @afourwide @c %*** End of the HEADER @c %*** Start of TITLEPAGE @titlepage @title OdePkg @value{VERSION} @subtitle A package for solving ordinary differential equations and more @c @subtitle @b{OdePkg and this document currently are under development} @author by Thomas Treichl @page @vskip 0pt plus 1filll Copyright @copyright{} 2006-2012, Thomas Treichl Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the same conditions as for modified versions. @end titlepage @c %*** End of TITLEPAGE @c %*** Start of BODY @contents @ifnottex @node Top, Beginners Guide, (dir), (dir) @top Copyright Copyright @copyright{} 2006-2012, Thomas Treichl Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the same conditions as for modified versions. @end ifnottex @menu * Beginners Guide:: Manual for users who are completely new to OdePkg * Users Guide:: Manual for users who are already familiar with OdePkg * Programmers Guide:: Manual for users who want to make changes to OdePkg * Function Index:: Reference about all functions from this package * Index:: OdePkg Reference @end menu @c %*** Start of first chapter: Beginners Guide @node Beginners Guide, Users Guide, Top, Top @chapter Beginners Guide @cindex Beginners guide The ``Beginners Guide'' is intended for users who are new to OdePkg and who want to solve differential equations with the Octave language and the package OdePkg. In this section it will be explained what OdePkg is about in @ref{About OdePkg} and how OdePkg grew up from the beginning in @ref{OdePkg history and roadmap}. In @ref{Installation and deinstallation} it is explained how OdePkg can be installed in Octave and how it can later be removed from Octave if it is not needed anymore. If you encounter problems while using OdePkg then have a look at @ref{Reporting Bugs} how these bugs can be reported. In the @ref{The "foo" example} a first example is explained. @menu * About OdePkg:: An introduction about OdePkg * OdePkg history and roadmap:: From the first OdePkg release to the future * Installation and deinstallation:: Setting up OdePkg on your system * Reporting Bugs:: Writing comments and bugs to the help list * The "foo" example:: A first example and where to go from here @end menu @node About OdePkg, OdePkg history and roadmap, Beginners Guide, Beginners Guide @section About OdePkg @cindex About OdePkg OdePkg is part of the @b{Octave Repository} (resp. the Octave--Forge project) that was initiated by Matthew W. Roberts and Paul Kienzle in the year 2000 and that is hosted at @url{http://octave.sourceforge.net}. Since then a lot of contributors joined this project and added a lot more packages and functions to further extend the capabilities of GNU Octave. @c The email from Matthew W. Roberts about Octave--forge can be found here: @c http://velveeta.che.wisc.edu/octave/lists/archive/octave-sources.2000/msg00110.html OdePkg includes commands for setting up various options, output functions etc. before solving a set of differential equations with the solver functions that are included. The package formerly was initiated in autumn 2006 to solve ordinary differential equations (ODEs) only but there are already improvements so that differential algebraic equations (DAEs) in explicit form and in implicit form (IDEs) and delay differential equations (DDEs) can also be solved. The goal of OdePkg is to have a package for solving differential equations that is mostly compatible to proprietary solver products. @node OdePkg history and roadmap, Installation and deinstallation, About OdePkg, Beginners Guide @section OdePkg history and roadmap @cindex history @cindex roadmap @multitable @columnfractions .25 .75 @item OdePkg Version 0.0.1 @tab The initial release was a modification of the old ``ode'' package that is hosted at Octave--Forge and that was written by Marc Compere somewhen between 2000 and 2001. The four variable step--size Runge--Kutta algorithms in three solver files and the three fixed step--size solvers have been merged. It was possible to set some options for these solvers. The four output--functions (@command{odeprint}, @command{odeplot}, @command{odephas2} and @command{odephas3}) have been added along with other examples that initially have not been there. @item OdePkg Version 0.1.x @tab The major milestone along versions 0.1.x was that four stable solvers have been implemented (ie. @command{ode23}, @command{ode45}, @command{ode54} and @command{ode78}) supporting all options that can be set for these kind of solvers and also all necessary functions for setting their options (eg. @command{odeset}, @command{odepkg_structure_check, odepkg_event_handle}). Since version 0.1.3 there is also source code available that interfaces the Fortran solver @file{dopri5.f} (that is written by Ernst Hairer and Gerhard Wanner, cf. @file{odepkg_mexsolver_dopri5.c} and the helper files @file{odepkgext.c} and @file{odepkgmex.c}). @item OdePkg Version 0.2.x @tab The main work along version 0.2.x was to make the interface functions for the non--stiff and stiff solvers from Ernst Hairer and Gerhard Wanner enough stable so that they could be compiled and installed by default. Wrapper functions have been added to the package containing a help text and test functions (eg. @command{ode2r}, @command{ode5r}, @command{oders}). Six testsuite functions have been added to check the performance of the different solvers (eg. @command{odepkg_testsuite_chemakzo}, @command{odepkg_testsuite_oregonator}). @item OdePkg Version 0.3.x @tab Fixed some minor bugs along version 0.3.x. Thanks to Jeff Cash, who released his Fortran @command{mebdfX} solvers under the GNU GPL V2 after some discussion. The first IDE solver @command{odebdi} appeared that is an interface function for Cash's @command{mebdfi} Fortran core solver. With version 0.3.5 of OdePkg a first new interface function was created based on Octave's C++ @code{DEFUN_DLD} interface to achieve the highest performance available. Added more examples and testsuite functions (eg. @command{odepkg_equations_ilorenz}, @command{odepkg_testsuite_implrober}). Porting all at this time present Mex--file solvers to Octave's C++ @code{DEFUN_DLD} interface. Ongoing work with this manual. @item OdePkg Version 0.4.x @tab Added a new solver function @command{odekdi} for the direct method (not the Krylov method) of the @file{daskr.f} solver from the authors Peter N. Brown, Alan C. Hindmarsh, Linda R. Petzold and Clement W. Ulrich that is available under a modified BSD license (without advertising clause). Ongoing work with this manual. @item OdePkg Version 0.5.x @tab Added new solver functions @command{ode23d}, @command{ode45d}, @command{ode54d} and @command{ode78d} for solving non--stiff delay differential equations (non-stiff DDEs). These solvers are based on the Runge--Kutta solvers @command{ode23}..@command{ode78}. Tests and demos have been included for this type of solvers. Added new functions @command{odeexamples}, @command{odepkg_examples_ode}, @command{odepkg_examples_dae}, @command{odepkg_examples_ide} and @command{odepkg_examples_ide}. Ongoing work with this manual. @item OdePkg Version 0.6.x @tab A lot of compatibility tests, improvements, bugfixes, etc. @item @b{(current)} Version 0.8.x @tab Final releases before version 1.0.0. @item @b{(future)} Version 1.0.0 @tab Completed OdePkg release 1.0.0 with M--solvers and DLD--solvers. @end multitable @node Installation and deinstallation, Reporting Bugs, OdePkg history and roadmap, Beginners Guide @section Installation and deinstallation @cindex installation @cindex deinstallation OdePkg can be installed easily using the @command{pkg} command in Octave. To install OdePkg download the latest release of OdePkg from the Octave--Forge download site, then get into that directory where the downloaded release of OdePkg has been saved, start Octave and type @example pkg install odepkg-x.x.x.tar.gz @end example where @file{x.x.x} in the name of the @file{*.tar.gz} file is the current release number of OdePkg that is available. If you want to deinstall resp. remove OdePkg then simply type @example pkg uninstall odepkg @end example and make sure that OdePkg has been removed completely and does not appear in the list of installed packages anymore with the following command @example pkg list @end example @node Reporting Bugs, The "foo" example, Installation and deinstallation, Beginners Guide @section Reporting Bugs @cindex bugs If you encounter problems during the installation process of OdePkg with the @command{pkg} command or if you have an OdePkg that seems to be broken or if you encounter problems while using OdePkg or if you find bugs in the source codes then please report all of that via email at the Octave--Forge mailing--list using the email address @ifnothtml @email{octave-dev@@lists.sourceforge.net}. @end ifnothtml @ifhtml @email{octave-dev @{at] lists.sourceforge.net} (replace @{at] with @@). @end ifhtml Not only bugs are welcome but also any kind of comments are welcome (eg. if you think that OdePkg is absolutely useful or even unnecessary). @node The "foo" example, , Reporting Bugs, Beginners Guide @section The "foo" example @cindex foo example Have a look at the first ordinary differential equation with the name ``@command{foo}''. The @command{foo} equation of second order may be of the form @ifhtml @example @math{y''(t) + C1 y'(t) + C2 y(t) = C3} @end example @end ifhtml @ifnothtml @math{y''(t) + C_1 y'(t) + C_2 y(t) = C_3}. @end ifnothtml With the substitutions @ifhtml @example @math{y1(t) = y(t)} @math{y2(t) = y'(t)} @end example @end ifhtml @ifnothtml @math{y_1(t) = y(t)} and @math{y_2(t) = y'(t)} @end ifnothtml this differential equation of second order can be split into two differential equations of first order, ie. @ifhtml @example @math{y1'(t) = y2(t)} @math{y2'(t) = - C1 y2(t) - C2 y1(t) + C3} @end example @end ifhtml @ifnothtml @math{y'_1(t) = y_2(t)} and @math{y'_2(t) = - C_1 y_2(t) - C_2 y_1(t) + C_3}. @end ifnothtml Next the numerical values for the constants need to be defined, ie. @ifhtml @example @math{C1 = 2.0} @math{C2 = 5.0} @math{C3 = 10.0} @end example @end ifhtml @ifnothtml @math{C_1 = 2.0}, @math{C_2 = 5.0}, @math{C_3 = 10.0}. @end ifnothtml This set of ordinary differential equations can then be written as an Octave M--file function like @example function vdy = foo (vt, vy, varargin) vdy(1,1) = vy(2); vdy(2,1) = - 2.0 * vy(2) - 5.0 * vy(1) + 10.0; endfunction @end example It can be seen that this ODEs do not depend on time, nevertheless the first input argument of this function needs to be defined as the time argument @var{vt} followed by a solution array argument @command{vy} as the second input argument and a variable size input argument @command{varargin} that can be used to set up user defined constants or control variables. As it is known that @command{foo} is a set of @i{ordinary} differential equations we can choose one of the four Runge--Kutta solvers (cf. @ref{Solver families}). It is also known that the time period of interest may be between @ifhtml @example @math{t0 = 0.0} @math{te = 5.0} @end example @end ifhtml @ifnothtml @math{t_0 = 0.0} and @math{t_e = 5.0} @end ifnothtml as well as that the initial values of the ODEs are @ifhtml @example @math{y1(t=0) = 0.0} @math{y2(t=0) = 0.0} @end example @end ifhtml @ifnothtml @math{y_1(t=0) = 0.0} and @math{y_2(t=0) = 0.0}. @end ifnothtml Solving this set of ODEs can be done by typing the following commands in Octave @example ode45 (@@foo, [0 5], [0 0]); @end example A figure window opens and it can be seen how this ODEs are solved over time. For some of the solvers that come with OdePkg it is possible to define exact time stamps for which an solution is required. Then the example can be called eg.@example ode45 (@@foo, [0:0.1:5], [0 0]); @end example If it is not wanted that a figure window is opened while solving then output arguments have to be used to catch the results of the solving process and to not pass the results to the figure window, eg. @example [t, y] = ode45 (@@foo, [0 5], [0 0]); @end example Results can also be obtained in form of an Octave structure if one output argument is used like in the following example. Then the results are stored in the fields @command{S.x} and @command{S.y}. @example S = ode45 (@@foo, [0 5], [0 0]); @end example As noticed before, a function for the ordinary differential equations must not be rewritten all the time if some of the parameters are going to change. That's what the input argument @command{varargin} can be used for. So rewrite the function @command{foo} into @command{newfoo} the following way @example function vdy = newfoo (vt, vy, varargin) vdy(1,1) = vy(2); vdy(2,1) = -varargin@{1@}*vy(2)-varargin@{2@}*vy(1)+varargin@{3@}; endfunction @end example There is nothing said anymore about the constant values but if using the following caller routine in the Octave window then the same results can be obtained with the new function @command{newfoo} as before with the function @command{foo} (ie. the parameters are directly feed through from the caller routine @command{ode45} to the function @command{newfoo}) @example ode45 (@@newfoo, [0 5], [0 0], 2.0, 5.0, 10.0); @end example OdePkg can do much more while solving differential equations, eg. setting up other output functions instead of the function @command{odeplot} or setting up other tolerances for the solving process etc. As a last example in this beginning chapter it is shown how this can be done, ie. with the command @command{odeset} @example A = odeset ('OutputFcn', @@odeprint); ode45 (@@newfoo, [0 5], [0 0], A, 2.0, 5.0, 10.0); @end example or @example A = odeset ('OutputFcn', @@odeprint, 'AbsTol', 1e-5, \ 'RelTol', 1e-5, 'NormControl', 'on'); ode45 (@@newfoo, [0 5], [0 0], A, 2.0, 5.0, 10.0); @end example The options structure @command{A} that can be set up with with the command @command{odeset} must always be the fourth input argument when using the ODE solvers and the DAE solvers but if you are using an IDE solver then @command{A} must be the fifth input argument (cf. @ref{Solver families}). The various options that can be set with the command @command{odeset} are described in @ref{ODE/DAE/IDE/DDE options}. Further examples have also been implemented. These example files and functions are of the form @command{odepkg_examples_*}. Different testsuite examples have been added that are stored in files with filenames @command{odepkg_testsuite_*}. Before reading the next chapter note that nearly every function that comes with OdePkg has its own help text and its own examples. Look for yourself how the different functions, options and combinations can be used. If you want to have a look at the help description of a special function then type @example help fcnname @end example in the Octave window where @command{fcnname} is the name of the function for the help text to be viewed. Type @example demo fcnname @end example in the Octave window where @command{fcnname} is the name of the function for the demo to run. Finally write @example doc odepkg @end example for opening this manual in the texinfo reader of the Octave window. @c %*** End of first chapter: Beginners Guide @c %*** Start of second chapter: Users Guide @node Users Guide, Programmers Guide, Beginners Guide, Top @chapter Users Guide @cindex Users guide The ``Users Guide'' is intended for trained users who already know in principal how to solve differential equations with the Octave language and OdePkg. In this chapter it will be explained which equations can be solved with OdePkg in @ref{Differential Equations}. It will be explained which solvers can be used for the different kind of equations in @ref{Solver families} and which options can be set for the optimization of the solving process in @ref{ODE/DAE/IDE/DDE options}. The help text of all M--file functions and all Oct--file functions have been extracted and are displayed in the sections @ref{M-File Function Reference} and @ref{Oct-File Function Reference}. @menu * Differential Equations:: The different kind of problems that can be solved with OdePkg * Solver families:: The different kind of solvers within OdePkg * ODE/DAE/IDE/DDE options:: The options that can be set for a solving process * M-File Function Reference:: The description about all @file{*.m}-file functions * Oct-File Function Reference:: The description about all DLD-functions from @file{*.oct}-files @end menu @node Differential Equations, Solver families, Users Guide, Users Guide @section Differential Equations @cindex differential equations In this section the different kind of differential equations that can be solved with OdePkg are explained. The formulation of ordinary differential equations is described in section @ref{ODE equations} followed by the description of explicetly formulated differential algebraic equations in section @ref{DAE equations}, implicetely formulated differential algebraic equations in section @ref{IDE equations} and delay differential algebraic equations in section @ref{DDE equations}. @menu * ODE equations:: Ordinary differential equations * DAE equations:: Differential algebraic equations in explicit form * IDE equations:: Differential algebraic equations in implicit form * DDE equations:: Delay differential equations @end menu @node ODE equations, DAE equations, Differential Equations, Differential Equations @subsection ODE equations @cindex ode equations ODE equations in general are of the form @ifhtml @example @math{y'(t) = f(t,y)} @end example @end ifhtml @ifnothtml @math{y'(t) = f(t,y)} @end ifnothtml where @math{y'(t)} may be a scalar or vector of derivatives. The variable @math{t} always is a scalar describing one point of time and the variable @math{y(t)} is a scalar or vector of solutions from the last time step of the set of ordinary differential equations. If the equation is non--stiff then the @ref{Runge-Kutta solvers} can be used to solve such kind of differential equations but if the equation is stiff then it is recommended to use the @ref{Hairer-Wanner solvers}. An ODE equation definition in Octave must look like @example function [dy] = ODEequation (t, y, varargin) @end example @node DAE equations, IDE equations, ODE equations, Differential Equations @subsection DAE equations @cindex dae equations DAE equations in general are of the form @ifhtml @example @math{M(t,y) y'(t) = f(t,y)} @end example @end ifhtml @ifnothtml @math{M(t,y) \cdot y'(t) = f(t,y)} @end ifnothtml where @math{y'(t)} may be a scalar or vector of derivatives. The variable @math{t} always is a scalar describing one point of time and the variable @math{y(t)} is a scalar or vector of solutions from the set of differential algebraic equations. The variable @math{M(t,y)} is the squared @i{singular} mass matrix that may depend on @math{y} and @math{t}. If @math{M(t,y)} is not @i{singular} then the set of equations from above can normally also be written as an ODE equation. If it does not depend on time then it can be defined as a constant matrix or a function. If it does depend on time then it must be defined as a function. Use the command @command{odeset} to pass the mass matrix information to the solver function (cf. @ref{ODE/DAE/IDE/DDE options}). If the equation is non--stiff then the @ref{Runge-Kutta solvers} can be used to solve such kind of differential equations but if the equation is stiff then it is recommended to use the @ref{Hairer-Wanner solvers}. A DAE equation definition in Octave must look like @example function [dy] = DAEequation (t, y, varargin) @end example and the mass matrix definition can either be a constant mass matrix or a valid function handle to a mass matrix calculation function that can be set with the command @command{odeset} (cf. option @code{Mass} of section @ref{ODE/DAE/IDE/DDE options}). @node IDE equations, DDE equations, DAE equations, Differential Equations @subsection IDE equations @cindex ide equations IDE equations in general are of the form @ifhtml @example @math{y'(t) + f(t,y) = 0} @end example @end ifhtml @ifnothtml @math{y'(t) + f(t,y) = 0} @end ifnothtml where @math{y'(t)} may be a scalar or vector of derivatives. The variable @math{t} always is a scalar describing one point of time and the variable @math{y(t)} is a scalar or vector of solutions from the set of implicit differential equations. Only IDE solvers from section @ref{Cash modified BDF solvers} or section @ref{DDaskr direct method solver} can be used to solve such kind of differential equations. A DAE equation definition in Octave must look like @example function [residual] = IDEequation (t, y, dy, varargin) @end example @node DDE equations, , IDE equations, Differential Equations @subsection DDE equations @cindex dde equations DDE equations in general are of the form @ifhtml @example @math{y'(t) = f(t,y(t),y(t-tau_1),...,y(t-tau_n))} @end example @end ifhtml @ifnothtml @math{y'(t) = f(t,y(t),y(t-\tau_1),...,y(t-\tau_n))} @end ifnothtml where @math{y'(t)} may be a scalar or vector of derivatives. The variable @math{t} always is a scalar describing one point of time and the variables @ifhtml @math{y(t-tau_i)} @end ifhtml @ifnothtml @math{y(t-\tau_i)} @end ifnothtml are scalars or vectors from the past. Only DDE solvers from section @ref{Modified Runge-Kutta solvers} can be used to solve such kind of differential equations. A DDE equation definition in Octave must look like @example function [dy] = DDEequation (t, y, z, varargin) @end example @b{NOTE:} Only DDEs with constant delays @ifhtml @math{y(t-tau_i)} @end ifhtml @ifnothtml @math{y(t-\tau_i)} @end ifnothtml can be solved with OdePkg. @node Solver families, ODE/DAE/IDE/DDE options, Differential Equations, Users Guide @section Solver families @cindex solver families In this section the different kind of solvers are introduced that have been implemented in OdePkg. This section starts with the basic Runge--Kutta solvers in section @ref{Runge-Kutta solvers} and is continued with the Mex--file Hairer--Wanner solvers in section @ref{Hairer-Wanner solvers}. @c Other solvers are described in section @ref{Other solvers}. Performance tests have also been added to the OdePkg. Some of these performance results have been added to section @ref{ODE solver performances}. @menu * Runge-Kutta solvers:: ODE solvers written as @file{*.m} files * Hairer-Wanner solvers:: DAE solvers interfaced by @file{*.cc} files * Cash modified BDF solvers:: A DAE and an IDE solver interfaced by @file{*.cc} files * DDaskr direct method solver:: An IDE solver interfaced by a @file{*.cc} file * Modified Runge-Kutta solvers:: DDE solvers written as @file{*.m} files * ODE solver performances:: Cross math-engine performance tests @end menu @node Runge-Kutta solvers, Hairer-Wanner solvers, Solver families, Solver families @subsection Runge--Kutta solvers @cindex Runge--Kutta The Runge--Kutta solvers are written in the Octave language and that are saved as @file{m}--files. There have been implemented four different solvers with a very similiar structure, ie. @command{ode23}, @command{ode45}, @command{ode54} and @command{ode78}@footnote{The descriptions for these Runge--Kutta solvers have been taken from the help texts of the initial Runge--Kutta solvers that were written by Marc Compere, he also pointed out that ''a relevant discussion on step size choice can be found on page 90ff in U.M. Ascher, L.R. Petzold, Computer Methods for Ordinary Differential Equations and Differential--Agebraic Equations, Society for Industrial and Applied Mathematics (SIAM), Philadelphia, 1998''.}. The Runge--Kutta solvers have been added to the OdePkg to solve non--stiff ODEs and DAEs, stiff equations of that form cannot be solved with these solvers. The order of all of the following Runge--Kutta methods is the order of the local truncation error, which is the principle error term in the portion of the Taylor series expansion that gets dropped, or intentionally truncated. This is different from the local error which is the difference between the estimated solution and the actual, or true solution. The local error is used in stepsize selection and may be approximated by the difference between two estimates of different order, @ifhtml @example @math{l(h) = x(O(h+1)) - x(O(h))} @end example @end ifhtml @ifnothtml @math{l(h) = x(O(h+1)) - x(O(h))}. @end ifnothtml With this definition, the local error will be as large as the error in the lower order method. The local truncation error is within the group of terms that gets multipled by @math{h} when solving for a solution from the general Runge--Kutta method. Therefore, the order--p solution created by the Runge--Kunge method will be roughly accurate to @ifhtml @example @math{O(h^{(p+1)})} @end example @end ifhtml @ifnothtml @math{O(h^{(p+1)})} @end ifnothtml since the local truncation error shows up in the solution as @ifhtml @example @math{e = h d} @end example @end ifhtml @ifnothtml @math{e = h\cdot d} @end ifnothtml which is @math{h}--times an @math{O(h^p)}--term, or rather @math{O(h^{(p+1)})}. @multitable @columnfractions .075 .925 @item @command{ode23} @tab Integrates a system of non--stiff ordinary differential equations (non--stiff ODEs and DAEs) using second and third order Runge--Kutta formulas. This particular third order method reduces to Simpson's @math{1/3} rule and uses the third order estimation for the output solutions. Third order accurate Runge--Kutta methods have local and global errors of @math{O(h^4)} and @math{O(h^3)} respectively and yield exact results when the solution is a cubic (the variable @math{h} is the step size from one integration step to another integration step). This solver requires three function evaluations per integration step.@* @item @command{ode45} @tab Integrates a system of non--stiff ordinary differential equations (non--stiff ODEs and DAEs) using fourth and fifth order embedded formulas from Fehlberg. This is a fourth--order accurate integrator therefore the local error normally expected is @math{O(h^5)}. However, because this particular implementation uses the fifth--order estimate for @math{x_{out}} (ie. local extrapolation) moving forward with the fifth--order estimate should yield local error of @math{O(h^6)}. This solver requires six function evaluations per integration step.@* @item @command{ode54} @tab Integrates a system of non--stiff ordinary differential equations (non--stiff ODEs and DAEs) using fifth and fourth order Runge--Kutta formulas. The Fehlberg @math{4(5)} of the @command{ode45} pair is established and works well, however, the Dormand--Prince @math{5(4)} pair minimizes the local truncation error in the fifth--order estimate which is what is used to step forward (local extrapolation). Generally it produces more accurate results and costs roughly the same computationally. This solver requires seven function evaluations per integration step.@* @item @command{ode78} @tab Integrates a system of non--stiff ordinary differential equations (non--stiff ODEs and DAEs) using seventh and eighth order Runge--Kutta formulas. This is a seventh--order accurate integrator therefore the local error normally expected is @math{O(h^8)}. However, because this particular implementation uses the eighth--order estimate for @math{x_{out}} moving forward with the eighth--order estimate will yield errors on the order of @math{O(h^9)}. This solver requires thirteen function evaluations per integration step. @end multitable @node Hairer-Wanner solvers, Cash modified BDF solvers, Runge-Kutta solvers, Solver families @subsection Hairer--Wanner solvers @cindex Hairer--Wanner The Hairer--Wanner solvers have been written by Ernst Hairer and Gerhard Wanner. They are written in the Fortran language (hosted at @url{http://www.unige.ch/~hairer}) and that have been added to the OdePkg as a compressed file with the name @file{hairer.tgz}. Papers and other details about these solvers can be found at the adress given before. The licence of these solvers is a modified BSD license (without advertising clause and therefore are GPL compatible) and can be found as @file{licence.txt} file in the @file{hairer.tgz} package. The Hairer--Wanner solvers have been added to the OdePkg to solve non--stiff and stiff ODEs and DAEs that cannot be solved with any of the Runge--Kutta solvers. Interface functions for these solvers have been created and have been added to the OdePkg. Their names are @file{odepkg_octsolver_XXX.cc} where @file{XXX} is the name of the Fortran file that is interfaced. The file @file{dldsolver.oct} is created automatically when installing OdePkg with the command @command{pkg}, but developers can also build each solver manually with the instructions given as a preamble of every @file{odepkg_octsolver_XXX.cc} file. To provide a short name and to circumvent from the syntax of the original solver function wrapper functions have been added, eg. the command @command{ode2r} calls the solver @command{radau} from the Fortran file @file{radau.f}. The other wrapper functions for the Hairer--Wanner solvers are @command{ode5r} for the @command{radau5} solver, @command{oders} for the @command{rodas} solver and @command{odesx} for the @command{seulex} solver. The help text of all these solver functions can be diaplyed by calling @command{help wrapper} where wrapper is one of @command{ode2r}, @command{ode5r}, @command{oders} or @command{odesx}. @node Cash modified BDF solvers, DDaskr direct method solver, Hairer-Wanner solvers, Solver families @subsection Cash modified BDF solvers @cindex BDF solver @cindex Cash modified BDF The backward differentiation algorithm solvers have been written by Jeff Cash in the Fortran language and that are hosted at @url{http://pitagora.dm.uniba.it/~testset}. They have been added to the OdePkg as a compressed file with the name @file{cash.tgz}. The license of these solvers is a General Public License V2 that can be found as a preamble of each Fortran solver source file. Papers and other details about these solvers can be found at the host adress given before and also at Jeff Cash's homepage at @url{http://www.ma.ic.ac.uk/~jcash}. Jeff Cash's modified BDF solvers have been added to the OdePkg to solve non--stiff and stiff ODEs and DAEs and also IDEs that cannot be solved with any of the Runge--Kutta solvers. Interface functions for these solvers have been created and have been added to the OdePkg. Their names are @file{odepkg_octsolver_XXX.cc} where @file{XXX} is the name of the Fortran file that is interfaced. The file @file{dldsolver.oct} is created automatically when installing OdePkg with the command @command{pkg}, but developers can also build each solver manually with the instructions given as a preamble of every @file{odepkg_octsolver_XXX.cc} file. To provide a short name and to circumvent from the syntax of the original solver function wrapper functions have been added. The command @command{odebda} calls the solver @command{mebdfdae} from the Fortran file @file{mebdf.f} and the @command{odebdi} calls the solver @command{mebdfi} from the Fortran file @file{mebdfi.f}. @node DDaskr direct method solver, Modified Runge-Kutta solvers, Cash modified BDF solvers, Solver families @subsection DDaskr direct method solver @cindex ddaskr solver The direct method from the Krylov solver file @file{ddaskr.f} has been written by Peter N. Brown, Alan C. Hindmarsh, Linda R. Petzold and Clement W. Ulrich in the Fortran language and that is hosted at @url{http://www.netlib.org}. @b{The Krylov method has not been implemented within OdePkg, only the direct method has been implemented.} The solver and further files for the interface have been added to the OdePkg as a compressed package with the name @file{ddaskr.tgz}. The license of these solvers is a modfied BSD license (without advertising clause) that can be found inside of the compressed package. Other details about this solver can be found as a preamble in the source file @file{ddaskr.f}. The direct method solver of the file @file{ddaskr.f} has been added to the OdePkg to solve non--stiff and stiff IDEs. An interface function for this solver has been created and has been added to the OdePkg. The source file name is @file{odepkg_octsolver_ddaskr.cc}. The binary function can be found in the file @file{dldsolver.oct} that is created automatically when installing OdePkg with the command @command{pkg}, but developers can also build the solver wrapper manually with the instructions given as a preamble of the @file{odepkg_octsolver_ddaskr.cc} file. To provide a short name and to circumvent from the syntax of the original solver function a wrapper function has been added. The command @command{odekdi} calls the direct method of the solver @command{ddaskr} from the Fortran file @file{ddaskr.f}. @node Modified Runge-Kutta solvers, ODE solver performances, DDaskr direct method solver, Solver families @subsection Modified Runge--Kutta solvers @cindex Runge--Kutta modified The modified Runge--Kutta solvers are written in the Octave language and that are saved as m--files. There have been implemented four different solvers that do have a very similiar structure to that solvers found in section @ref{Runge-Kutta solvers}. Their names are @command{ode23d}, @command{ode45d}, @command{ode54d} and @command{ode78d}. The modified Runge--Kutta solvers have been added to the OdePkg to solve non--stiff DDEs with constant delays only, stiff equations of that form cannot be solved with these solvers. For further information about the error estimation of these solvers cf. section @ref{Runge-Kutta solvers}. @b{Note:} The four DDE solvers of OdePkg are not syntax compatible to propietary solvers. The reason is that the input arguments of the propietary DDE--solvers are completely mixed up in comparison to ODE, DAE and IDE propietary solvers. The DDE solvers of OdePkg have been implemented in form of a syntax compatible way to the other family solvers, eg. propietary solver calls look like @example ode23 (@@fode, vt, vy) %# for solving an ODE ode15i (@@fide, vt, vy, vdy) %# for solving an IDE dde23 (@@fdde, vlag, vhist, vt) %# for solving a DDE @end example whereas in OdePkg the same examples would look like @example ode23 (@@fode, vt, vy) %# for solving an ODE odebdi (@@fide, vt, vy, vdy) %# for solving an IDE ode23d (@@fdde, vt, vy, vlag, vhist) %# for solving a DDE @end example Further, the commands @command{ddeset} and @command{ddeget} have not been implemented in OdePkg. Use the functions @command{odeset} and @command{odeget} for setting and returning DDE options instead. @node ODE solver performances, , Modified Runge-Kutta solvers, Solver families @subsection ODE solver performances @cindex performance The following tables give an overview about the performance of the OdePkg ODE/DAE solvers in comparison to propietary solvers when running the HIRES function from the OdePkg testsuite (non--stiff ODE test). @smallexample >> odepkg ('odepkg_performance_mathires'); ----------------------------------------------------------------------------------------- Solver RelTol AbsTol Init Mescd Scd Steps Accept FEval JEval LUdec Time ----------------------------------------------------------------------------------------- ode113 1e-007 1e-007 1e-009 7.57 5.37 24317 21442 45760 11.697 ode23 1e-007 1e-007 1e-009 7.23 5.03 13876 13862 41629 2.634 ode45 1e-007 1e-007 1e-009 7.91 5.70 11017 10412 66103 2.994 ode15s 1e-007 1e-007 1e-009 7.15 4.95 290 273 534 8 59 0.070 ode23s 1e-007 1e-007 1e-009 6.24 4.03 702 702 2107 702 702 0.161 ode23t 1e-007 1e-007 1e-009 6.00 3.79 892 886 1103 5 72 0.180 ode23tb 1e-007 1e-007 1e-009 5.85 3.65 735 731 2011 5 66 0.230 ----------------------------------------------------------------------------------------- @end smallexample @smallexample octave:1> odepkg ('odepkg_performance_octavehires'); ----------------------------------------------------------------------------------------- Solver RelTol AbsTol Init Mescd Scd Steps Accept FEval JEval LUdec Time ----------------------------------------------------------------------------------------- ode23 1e-07 1e-07 1e-09 7.86 5.44 17112 13369 51333 138.071 ode45 1e-07 1e-07 1e-09 8.05 5.63 9397 9393 56376 92.065 ode54 1e-07 1e-07 1e-09 8.25 5.83 9300 7758 65093 84.319 ode78 1e-07 1e-07 1e-09 8.54 6.12 7290 6615 94757 97.746 ode2r 1e-07 1e-07 1e-09 7.69 5.27 50 50 849 50 59 0.624 ode5r 1e-07 1e-07 1e-09 7.55 5.13 71 71 671 71 81 0.447 oders 1e-07 1e-07 1e-09 7.08 4.66 138 138 828 138 138 0.661 odesx 1e-07 1e-07 1e-09 6.56 4.13 30 26 1808 26 205 1.057 odebda 1e-07 1e-07 1e-09 6.53 4.11 401 400 582 42 42 0.378 ----------------------------------------------------------------------------------------- @end smallexample The following tables give an overview about the performance of the OdePkg ODE/DAE solvers in comparison to propietary solvers when running the chemical AKZO--NOBEL function from the OdePkg testsuite (non--stiff ODE test). @smallexample >> odepkg ('odepkg_performance_matchemakzo'); ----------------------------------------------------------------------------------------- Solver RelTol AbsTol Init Mescd Scd Steps Accept FEval JEval LUdec Time ----------------------------------------------------------------------------------------- ode113 1e-007 1e-007 1e-007 NaN Inf - - - - - - ode23 1e-007 1e-007 1e-007 NaN Inf 15 15 47 0.431 ode45 1e-007 1e-007 1e-007 NaN Inf 15 15 92 0.170 ode15s 1e-007 1e-007 1e-007 7.04 6.20 161 154 4 35 0.521 ode23s 1e-007 1e-007 1e-007 7.61 6.77 1676 1676 5029 1676 1677 2.704 ode23t 1e-007 1e-007 1e-007 5.95 5.11 406 404 3 39 0.611 ode23tb 1e-007 1e-007 1e-007 NaN Inf 607 3036 1 608 6.730 ----------------------------------------------------------------------------------------- @end smallexample @smallexample octave:1> odepkg ('odepkg_performance_octavechemakzo'); ----------------------------------------------------------------------------------------- Solver RelTol AbsTol Init Mescd Scd Steps Accept FEval JEval LUdec Time ----------------------------------------------------------------------------------------- ode23 1e-07 1e-07 1e-07 2.95 2.06 424 385 1269 1.270 ode45 1e-07 1e-07 1e-07 2.95 2.06 256 218 1530 1.281 ode54 1e-07 1e-07 1e-07 2.95 2.06 197 195 1372 1.094 ode78 1e-07 1e-07 1e-07 2.95 2.06 184 156 2379 1.933 ode2r 1e-07 1e-07 1e-07 8.50 7.57 39 39 372 39 43 0.280 ode5r 1e-07 1e-07 1e-07 8.50 7.57 39 39 372 39 43 0.238 oders 1e-07 1e-07 1e-07 7.92 7.04 67 66 401 66 67 0.336 odesx 1e-07 1e-07 1e-07 7.19 6.26 19 19 457 19 82 0.248 odebda 1e-07 1e-07 1e-07 7.47 6.54 203 203 307 25 25 0.182 ----------------------------------------------------------------------------------------- @end smallexample Other testsuite functions have been added to the OdePkg that can be taken for further performance tests and syntax checks on your own hardware. These functions all have a name @file{odepkg_testsuite_XXX.m} with @file{XXX} being the name of the testsuite equation that has been implemented. @node ODE/DAE/IDE/DDE options, M-File Function Reference, Solver families, Users Guide @section ODE/DAE/IDE/DDE options @cindex ode options @cindex dae options @cindex ide options @cindex dde options The default values of an OdePkg options structure can be displayed with the command @command{odeset}. If @command{odeset} is called without any input argument and one output argument then a OdePkg options structure with default values is created, eg. @example A = odeset (); disp (A); @end example There also is an command @command{odeget} which extracts one or more options from an OdePkg options structure. Other values than default values can also be set with the command @command{odeset}. The function description of the commands @command{odeset} and @command{odeget} can be found in the @ref{M-File Function Reference}. The values that can be set with the @command{odeset} command are @table @samp @item RelTol @cindex RelTol option The option @option{RelTol} is used to set the relative error tolerance for the error estimation of the solver that is used while solving. It can either be a positive scalar or a vector with every element of the vector being a positive scalar (this depends on the solver that is used if both variants are supported). The definite error estimation equation also depends on the solver that is used but generalized (eg. for the solvers @command{ode23}, @command{ode45}, @command{ode54} and @command{ode78}) it may be a form like @ifhtml @example @math{e(t) = max (RelTol^T y(t), AbsTol)} @end example @end ifhtml @ifnothtml @math{e(t) = max (r_{tol}^T y(t), a_{tol})}. @end ifnothtml Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("RelTol", 1, "OutputFcn", @@odeplot); ode78 (@@fvanderpol, [0 20], [2 0], A); B = odeset (A, "RelTol", 1e-10); ode78 (@@fvanderpol, [0 20], [2 0], B); @end example @item AbsTol @cindex AbsTol option The option @option{AbsTol} is used to set the absolute error tolerance for the error estimation of the solver that is used while solving. It can either be a positive scalar or a vector with every element of the vector being a positive scalar (it depends on the solver that is used if both variants are supported). The definite error estimation equation also depends on the solver that is used but generalized (eg. for the solvers @command{ode23}, @command{ode45}, @command{ode54} and @command{ode78}) it may be a form like @ifhtml @example @math{e(t) = max (RelTol^T y(t), AbsTol)} @end example @end ifhtml @ifnothtml @math{e(t) = max (r_{tol}^T y(t), a_{tol})}. @end ifnothtml Run the following example to illustrate the effect if this option is used @example ## An anonymous implementation of the Van der Pol equation fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; A = odeset ("AbsTol", 1e-3, "OutputFcn", @@odeplot); ode54 (fvdb, [0 10], [2 0], A); B = odeset (A, "AbsTol", 1e-10); ode54 (fvdb, [0 10], [2 0], B); @end example @item NormControl @cindex NormControl option The option @option{NormControl} is used to set the type of error tolerance calculation of the solver that is used while solving. It can either be the string @command{"on"} or @command{"off"}. At the time the solver starts solving a warning message may be displayed if the solver will ignore the @command{"on"} setting of this option because of an unhandled resp. missing implementation. If set @command{"on"} then the definite error estimation equation also depends on the solver that is used but generalized (eg. for the solvers @command{ode23}, @command{ode45}, @command{ode54} and @command{ode78}) it may be a form like @ifhtml @example @math{e(t) = max (RelTol^T max (norm (y(t), Inf)), AbsTol)} @end example @end ifhtml @ifnothtml @math{e(t) = max (r_{tol}^T max (norm (y(t), \infty{})), a_{tol})}. @end ifnothtml Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("NormControl", "on", "OutputFcn", @@odeplot); ode78 (@@fvanderpol, [0 20], [2 0], A); B = odeset (A, "NormControl", "off"); ode78 (@@fvanderpol, [0 20], [2 0], B); @end example @item MaxStep @cindex MaxStep option The option @option{MaxStep} is used to set the maximum step size for the solver that is used while solving. It can only be a positive scalar. By default this value is set internally by every solver and also may differ when using different solvers. Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("MaxStep", 10, "OutputFcn", @@odeprint); ode78 (@@fvanderpol, [0 20], [2 0], A); B = odeset (A, "MaxStep", 1e-1); ode78 (@@fvanderpol, [0 20], [2 0], B); @end example @item InitialStep @cindex InitialStep option The option @option{InitialStep} is used to set the initial first step size for the solver. It can only be a positive scalar. By default this value is set internally by every solver and also may be different when using different solvers. Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("InitialStep", 1, "OutputFcn", @@odeprint); ode78 (@@fvanderpol, [0 1], [2 0], A); B = odeset (A, "InitialStep", 1e-5); ode78 (@@fvanderpol, [0 1], [2 0], B); @end example @item InitialSlope @cindex InitialSlope option The option @option{InitialSlope} is not handled by any of the solvers by now.@* @item OutputFcn @cindex OutputFcn option The option @option{OutputFcn} can be used to set up an output function for displaying the results of the solver while solving. It must be a function handle to a valid function. There are four predefined output functions available with OdePkg. @command{odeprint} prints the actual time values and results in the Octave window while solving, @command{odeplot} plots the results over time in a new figure window while solving, @command{odephas2} plots the first result over the second result as a two--dimensional plot while solving and @command{odephas3} plots the first result over the second result over the third result as a three--dimensional plot while solving. Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("OutputFcn", @@odeprint); ode78 (@@fvanderpol, [0 2], [2 0], A); @end example User defined output functions can also be used. A typical framework for a self--made output function may then be of the form @example function [vret] = odeoutput (vt, vy, vdeci, varargin) switch vdeci case "init" ## Do everything needed to intialize output function case "calc" ## Do everything needed to create output case "done" ## Do everything needed to clean up output function endswitch endfunction @end example The output function @command{odeplot} is also set automatically if the solver calculation routine is called without any output argument. Run the following example to illustrate the effect if this option is not used and no output argument is given @example ## An anonymous implementation of the Van der Pol equation fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; ode78 (fvdb, [0 20], [2 0]); @end example @item Refine @cindex Refine option The option @option{Refine} is used to set the interpolation factor that is used to increase the quality for the output values if an output function is also set with the option @option{OutputFcn}. It can only be a integer value @math{0<=}@option{Refine}@math{<=5}. Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("Refine", 0, "OutputFcn", @@odeplot); ode78 (@@fvanderpol, [0 20], [2 0], A); B = odeset (A, "Refine", 3); ode78 (@@fvanderpol, [0 20], [2 0], B); @end example @item OutputSel @cindex OutputSel option The option @option{OutputSel} is used to set the components for which output has to be performed if an output function is also set with the option @option{OutputFcn}. It can only be a vector of integer values. Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("OutputSel", [1, 2], "OutputFcn", @@odeplot); ode78 (@@fvanderpol, [0 20], [2 0], A); B = odeset (A, "OutputSel", [2]); ode78 (@@fvanderpol, [0 20], [2 0], B); @end example @item Stats @cindex Stats option The option @option{Stats} is used to print cost statistics about the solving process after solving has been finished. It can either be the string @command{"on"} or @command{"off"}. Run the following example to illustrate the effect if this option is used @example function yd = fvanderpol (vt, vy, varargin) mu = 1; ## Set mu > 10 for higher stiffness yd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction A = odeset ("Stats", "off"); [a, b] = ode78 (@@fvanderpol, [0 2], [2 0], A); B = odeset ("Stats", "on"); [c, d] = ode78 (@@fvanderpol, [0 2], [2 0], B); @end example The cost statistics can also be obtained if the solver calculation routine is called with one output argument. The cost statistics then are in the field @option{stats} of the output arguemnt structure. Run the following example to illustrate the effect if this option is used @example S = ode78 (@@fvanderpol, [0 2], [2 0], B); disp (S); @end example @item Jacobian @cindex Jacobian option The option @option{Jacobian} can be used to set up an external Jacobian function or Jacobian matrix for DAE solvers to achieve faster and better results (ODE Runge--Kutta solvers do not need to handle a Jacobian function handle or Jacobian matrix). It must either be a function handle to a valid function or a full constant matrix of size squared the dimension of the set of differential equations. User defined Jacobian functions must have the form @samp{function [vjac] = fjac (vt, vy, varargin)}. Run the following example to illustrate the effect if this option is used @example function vdy = fpol (vt, vy, varargin) vdy = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; endfunction function vr = fjac (vt, vy, varargin) vr = [0, 1; ... -1-2*vy(1)*vy(2), 1-vy(1)^2]; endfunction A = odeset ("Stats", "on"); B = ode5r (@@fpol, [0 20], [2 0], A); C = odeset (A, "Jacobian", @@fjac); D = ode5r (@@fpol, [0 20], [2 0], C); @end example @b{Note:} The function definition for Jacobian calculations of IDE equations must have the form @samp{function [vjac, vdjc] = fjac (vt, vy, vyd, varargin)}. Run the following example to illustrate the effect if this option is used @example function [vres] = fvanderpol (vt, vy, vyd, varargin) vres = [vy(2) - vyd(1); (1 - vy(1)^2) * vy(2) - vy(1) - vyd(2)]; endfunction function [vjac, vdjc] = fjacobian (vt, vy, vyd, varargin) vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; vdjc = [-1, 0; 0, -1]; endfunction vopt = odeset ("Jacobian", @@fjacobian, "Stats", "on"); vsol = odebdi (@@fvanderpol, [0, 20], [2; 0], [0; -2], vopt, 10); @end example @item JPattern @cindex JPattern option The option @option{JPattern} is not handled by any of the solvers by now.@* @item Vectorized @cindex Vectorized option The option @option{Vectorized} is not handled by any of the solvers by now.@* @item Mass @cindex Mass option The option @option{Mass} can be used to set up an external Mass function or Mass matrix for solving DAE equations. It depends on the solver that is used if @option{Mass} is supported or not. It must either be a function handle to a valid function or a full constant matrix of size squared the dimension of the set of differential equations. User defined Jacobian functions must have the form @samp{function vmas = fmas (vt, vy, varargin)}. Run the following example to illustrate the effect if this option is used @example function vdy = frob (t, y, varargin) vdy(1,1) = -0.04*y(1)+1e4*y(2)*y(3); vdy(2,1) = 0.04*y(1)-1e4*y(2)*y(3)-3e7*y(2)^2; vdy(3,1) = y(1)+y(2)+y(3)-1; endfunction function vmas = fmas (vt, vy, varargin) vmas = [1, 0, 0; 0, 1, 0; 0, 0, 0]; endfunction A = odeset ("Mass", @@fmas); B = ode5r (@@frob, [0 1e8], [1 0 0], A); @end example @b{Note:} The function definition for Mass calculations of DDE equations must have the form @samp{function vmas = fmas (vt, vy, vz, varargin)}.@* @item MStateDependence @cindex MStateDependence option The option @option{MStateDependence} can be used to set up the type of the external Mass function for solving DAE equations if a Mass function handle is set with the option @option{Mass}. It depends on the solver that is used if @option{MStateDependence} is supported or not. It must be a string of the form @command{"none"}, @command{"weak"} or @command{"strong"}. Run the following example to illustrate the effect if this option is used @example function vdy = frob (vt, vy, varargin) vdy(1,1) = -0.04*vy(1)+1e4*vy(2)*vy(3); vdy(2,1) = 0.04*vy(1)-1e4*vy(2)*vy(3)-3e7*vy(2)^2; vdy(3,1) = vy(1)+vy(2)+vy(3)-1; endfunction function vmas = fmas (vt, varargin) vmas = [1, 0, 0; 0, 1, 0; 0, 0, 0]; endfunction A = odeset ("Mass", @@fmas, "MStateDependence", "none"); B = ode5r (@@frob, [0 1e8], [1 0 0], A); @end example User defined Mass functions must have the form as described before (ie. @samp{function vmas = fmas (vt, varargin)} if the option @option{MStateDependence} was set to @command{"none"}, otherwise the user defined Mass function must have the form @samp{function vmas = fmas (vt, vy, varargin)} if the option @option{MStateDependence} was set to either @command{"weak"} or @command{"strong"}.@* @item MvPattern @cindex MvPattern option The option @option{MvPattern} is not handled by any of the solvers by now.@* @item MassSingular @cindex MassSingular option The option @option{MassSingular} is not handled by any of the solvers by now.@* @item NonNegative @cindex NonNegative option The option @option{NonNegative} can be used to set solution variables to zero even if their real solution would be a negative value. It must be a vector describing the positions in the solution vector for which the option @option{NonNegative} should be used. Run the following example to illustrate the effect if this option is used @example vfun = @@(vt,vy) -abs(vy); vopt = odeset ("NonNegative", [1]); [vt1, vy1] = ode78 (vfun, [0 100], [1]); [vt2, vy2] = ode78 (vfun, [0 100], [1], vopt); subplot (2,1,1); plot (vt1, vy1); subplot (2,1,2); plot (vt2, vy2); @end example @item Events @cindex Events option The option @option{Events} can be used to set up an Event function, ie. the Event function can be used to find zero crossings in one of the results. It must either be a function handle to a valid function. Run the following example to illustrate the effect if this option is used @example function vdy = fbal (vt, vy, varargin) vdy(1,1) = vy(2); vdy(2,1) = -9.81; ## m/s² endfunction function [veve, vterm, vdir] = feve (vt, vy, varargin) veve = vy(1); ## Which event component should be tread vterm = 1; ## Terminate if an event is found vdir = -1; ## In which direction, -1 for falling endfunction A = odeset ("Events", @@feve); B = ode78 (@@fbal, [0 1.5], [1 3], A); plot (B.x, B.y(:,1)); @end example @b{Note:} The function definition for Events calculations of DDE equations must have the form @samp{function [veve, vterm, vdir] = feve (vt, vy, vz, varargin)} and the function definition for Events calculations of IDE equations must have the form @samp{function [veve, vterm, vdir] = feve (vt, vy, vyd, varargin)}.@* @item MaxOrder @cindex MaxOrder option The option @option{MaxOrder} can be used to set the maximum order of the backward differentiation algorithm of the @command{odebdi} and @command{odebda} solvers. It must be a scalar integer value between @math{1} and @math{7}. Run the following example to illustrate the effect if this option is used @example function res = fwei (t, y, yp, varargin) res = t*y^2*yp^3 - y^3*yp^2 + t*yp*(t^2 + 1) - t^2*y; endfunction function [dy, dyp] = fjac (t, y, yp, varargin) dy = 2*t*y*yp^3 - 3*y^2*yp^2 - t^2; dyp = 3*t*y^2*yp^2 - 2*y^3*yp + t*(t^2 + 1); endfunction A = odeset ("AbsTol", 1e-6, "RelTol", 1e-6, "Jacobian", @@fjac, ... "Stats", "on", "MaxOrder", 1, "BDF", "on") B = odeset (A, "MaxOrder", 5) C = odebdi (@@fwei, [1 10], 1.2257, 0.8165, A); D = odebdi (@@fwei, [1 10], 1.2257, 0.8165, B); plot (C.x, C.y, "bo-", D.x, D.y, "rx:"); @end example @item BDF @cindex BDF option The option @option{BDF} is only supported by the @command{odebdi} and @command{odebda} solvers. Using these solvers the option @option{BDF} will automatically be set @command{"on"} (even if it was set @command{"off"} before) because the @command{odebdi} and @command{odebda} solvers all use the backward differentiation algorithm to solve the different kind of equations. @item NewtonTol @cindex NewtonTol option TODO @item MaxNewtonIterations @cindex MaxNewtonIterations option TODO @end table @node M-File Function Reference, Oct-File Function Reference, ODE/DAE/IDE/DDE options, Users Guide @section M--File Function Reference @cindex m--file reference The help texts of this section are autogenerated and refer to commands that all can be found in the files @file{*.m}. All commands that are listed below are loaded automatically everytime you launch Octave.@*@* @include mfunref.texi @node Oct-File Function Reference, , M-File Function Reference, Users Guide @section Oct--File Function Reference @cindex oct--file reference The help texts of this section are autogenerated and refer to commands that all can be found in the file @file{dldsolver.oct}. The file @file{dldsolver.oct} is generated automatically if you install OdePkg with the command @command{pkg}. All commands that are listed below are loaded automatically everytime you launch Octave.@*@* @include dldfunref.texi @c %*** End of second chapter: Users Guide @c %*** Start of third chapter: Programmers Guide @node Programmers Guide, Function Index, Users Guide, Top @chapter Programmers Guide @cindex Programmers guide @menu * Missing features:: The TODO-list for missing features @end menu @node Missing features, , Programmers Guide, Programmers Guide @section Missing features @cindex missing features If somebody want to help improving OdePkg then please contact the Octave--Forge developer team sending your modifications via the mailing--list @ifnothtml @email{octave-dev@@lists.sourceforge.net}. @end ifnothtml @ifhtml @email{octave-dev > OdePkg OdePkg Tutorial odepkg OdePkg ODE Solver Functions ode23 ode23s ode45 ode54 ode78 OdePkg DAE Solver Functions ode2r ode5r odebda odebwe oders odesx OdePkg IDE Solver Functions odebdi odekdi OdePkg DDE Solver Functions ode23d ode45d ode54d ode78d OdePkg Options Functions odeset odeget OdePkg Output Functions odeplot odeprint odephas2 odephas3 OdePkg Example Functions odeexamples odepkg_examples_dae odepkg_examples_dde odepkg_examples_ide odepkg_examples_ode OdePkg Testsuite Functions odepkg_testsuite_calcscd odepkg_testsuite_calcmescd odepkg_testsuite_chemakzo odepkg_testsuite_hires odepkg_testsuite_implakzo odepkg_testsuite_implrober odepkg_testsuite_impltrans odepkg_testsuite_oregonator odepkg_testsuite_pollution odepkg_testsuite_robertson odepkg_testsuite_transistor OdePkg Internal Functions odepkg_event_handle odepkg_structure_check OdePkg Other Functions bvp4codepkg/inst/0000755000176000010400000000000012111634317014162 5ustar marcoAdministratorsodepkg/inst/bvp4c.m0000644000176000010400000001356711711232766015401 0ustar marcoAdministrators## Copyright (C) 2008-2012 Carlo de Falco ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{A}} = bvp4c (@var{odefun}, @var{bcfun}, @var{solinit}) ## ## Solves the first order system of non-linear differential equations defined by ## @var{odefun} with the boundary conditions defined in @var{bcfun}. ## ## The structure @var{solinit} defines the grid on which to compute the ## solution (@var{solinit.x}), and an initial guess for the solution (@var{solinit.y}). ## The output @var{sol} is also a structure with the following fields: ## @itemize ## @item @var{sol.x} list of points where the solution is evaluated ## @item @var{sol.y} solution evaluated at the points @var{sol.x} ## @item @var{sol.yp} derivative of the solution evaluated at the ## points @var{sol.x} ## @item @var{sol.solver} = "bvp4c" for compatibility ## @end itemize ## @seealso{odpkg} ## @end deftypefn ## Author: Carlo de Falco ## Created: 2008-09-05 function sol = bvp4c(odefun,bcfun,solinit,options) if (isfield(solinit,"x")) t = solinit.x; else error("bvp4c: missing initial mesh solinit.x"); end if (isfield(solinit,"y")) u_0 = solinit.y; else error("bvp4c: missing initial guess"); end if (isfield(solinit,"parameters")) error("bvp4c: solving for unknown parameters is not yet supported"); end RelTol = 1e-3; AbsTol = 1e-6; if ( nargin > 3 ) if (isfield(options,"RelTol")) RelTol = options.RelTol; endif if (isfield(options,"RelTol")) AbsTol = options.AbsTol; endif endif Nvar = rows(u_0); Nint = length(t)-1; s = 3; h = diff(t); AbsErr = inf; RelErr = inf; MaxIt = 10; for iter = 1:MaxIt x = [ u_0(:); zeros(Nvar*Nint*s,1) ]; x = __bvp4c_solve__ (t, x, h, odefun, bcfun, Nvar, Nint, s); u = reshape(x(1:Nvar*(Nint+1)),Nvar,Nint+1); for kk=1:Nint+1 du(:,kk) = odefun(t(kk), u(:,kk)); end tm = (t(1:end-1)+t(2:end))/2; um = []; for nn=1:Nvar um(nn,:) = interp1(t,u(nn,:),tm); endfor f_est = []; for kk=1:Nint f_est(:,kk) = odefun(tm(kk), um(:,kk)); end du_est = []; for nn=1:Nvar du_est(nn,:) = diff(u(nn,:))./h; end err = max(abs(f_est-du_est)); semilogy(tm,err), pause(.1) AbsErr = max(err) RelErr = AbsErr/norm(du,inf) if ( (AbsErr >= AbsTol) && (RelErr >= RelTol) ) ref_int = find( (err >= AbsTol) & (err./max(max(abs(du))) >= RelTol) ); t_add = tm(ref_int); t_old = t; t = sort([t, t_add]); h = diff(t); u_0 = []; for nn=1:Nvar u_0(nn,:) = interp1(t_old, u(nn,:), t); end Nvar = rows(u_0); Nint = length(t)-1 else break end endfor ## K = reshape(x([1:Nvar*Nint*s]+Nvar*(Nint+1)),Nvar,Nint,s); ## K1 = reshape(K(:,:,1), Nvar, Nint); ## K2 = reshape(K(:,:,2), Nvar, Nint); ## K3 = reshape(K(:,:,3), Nvar, Nint); sol.x = t; sol.y = u; sol.yp= du; sol.parameters = []; sol.solver = 'bvp4c'; endfunction function diff_K = __bvp4c_fun_K__ (t, u, Kin, f, h, s, Nint, Nvar) %% coefficients persistent C = [0 1/2 1 ]; persistent A = [0 0 0; 5/24 1/3 -1/24; 1/6 2/3 1/6]; for jj = 1:s for kk = 1:Nint Y = repmat(u(:,kk),1,s) + ... (reshape(Kin(:,kk,:),Nvar,s) * A.') * h(kk); diff_K(:,kk,jj) = Kin(:,kk,jj) - f (t(kk)+C(jj)*h(kk), Y); endfor endfor endfunction function diff_u = __bvp4c_fun_u__ (t, u, K, h, s, Nint, Nvar) %% coefficients persistent B= [1/6 2/3 1/6 ]; Y = zeros(Nvar, Nint); for jj = 1:s Y += B(jj) * K(:,:,jj); endfor diff_u = u(:,2:end) - u(:,1:end-1) - repmat(h,Nvar,1) .* Y; endfunction function x = __bvp4c_solve__ (t, x, h, odefun, bcfun, Nvar, Nint, s) fun = @( x ) ( [__bvp4c_fun_u__(t, reshape(x(1:Nvar*(Nint+1)),Nvar,(Nint+1)), reshape(x([1:Nvar*Nint*s]+Nvar*(Nint+1)),Nvar,Nint,s), h, s, Nint, Nvar)(:) ; __bvp4c_fun_K__(t, reshape(x(1:Nvar*(Nint+1)),Nvar,(Nint+1)), reshape(x([1:Nvar*Nint*s]+Nvar*(Nint+1)),Nvar,Nint,s), odefun, h, s, Nint, Nvar)(:); bcfun(reshape(x(1:Nvar*(Nint+1)),Nvar,Nint+1)(:,1), reshape(x(1:Nvar*(Nint+1)),Nvar,Nint+1)(:,end)); ] ); x = fsolve ( fun, x ); endfunction %!demo %! a = 0; %! b = 4; %! Nint = 3; %! Nvar = 2; %! s = 3; %! t = linspace(a,b,Nint+1); %! h = diff(t); %! u_1 = ones(1, Nint+1); %! u_2 = 0*u_1; %! u_0 = [u_1 ; u_2]; %! f = @(t,u) [ u(2); -abs(u(1)) ]; %! g = @(ya,yb) [ya(1); yb(1)+2]; %! solinit.x = t; solinit.y=u_0; %! sol = bvp4c(f,g,solinit); %! plot (sol.x,sol.y,'x-') %!demo %! a = 0; %! b = 4; %! Nint = 2; %! Nvar = 2; %! s = 3; %! t = linspace(a,b,Nint+1); %! h = diff(t); %! u_1 = -ones(1, Nint+1); %! u_2 = 0*u_1; %! u_0 = [u_1 ; u_2]; %! f = @(t,u) [ u(2); -abs(u(1)) ]; %! g = @(ya,yb) [ya(1); yb(1)+2]; %! solinit.x = t; solinit.y=u_0; %! sol = bvp4c(f,g,solinit); %! plot (sol.x,sol.y,'x-') odepkg/inst/ode23.m0000644000176000010400000010276211742512661015272 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode23 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode23 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode23 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (2,3). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example, solve an anonymous implementation of the Van der Pol equation %# %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# %# vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ %# "NormControl", "on", "OutputFcn", @@odeplot); %# ode23 (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} %# ChangeLog: %# 20010703 the function file "ode23.m" was written by Marc Compere %# under the GPL for the use with this software. This function has been %# taken as a base for the following implementation. %# 20060810, Thomas Treichl %# This function was adapted to the new syntax that is used by the %# new OdePkg for Octave and is compatible to Matlab's ode23. function [varargout] = ode23 (vfun, vslot, vinit, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode23'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 3) print_usage; elseif ~(isa (vfun, 'function_handle') || isa (vfun, 'inline')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (nargin >= 4) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode23'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode23'); vfunarguments = {}; end else %# if (nargin == 3) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options are set in %# vodeoptions, check if an invalid or unused option is set vslot = vslot(:).'; %# Create a row vector vinit = vinit(:).'; %# Create a row vector if (length (vslot) > 2) %# Step size checking vstepsizefixed = true; else vstepsizefixed = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizefixed) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizefixed) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else vodeoptions.AbsTol = vodeoptions.AbsTol(:); %# Create column vector end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')) vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidArgument', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option OutputSave has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputSave)), vodeoptions.OutputSave = 1; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (vodeoptions.Refine > 0), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizefixed) vodeoptions.InitialStep = (vslot(1,2) - vslot(1,1)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidArgument', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizefixed) vodeoptions.MaxStep = abs (vslot(1,2) - vslot(1,1)) / 10; warning ('OdePkg:InvalidArgument', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidArgument', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidArgument', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidArgument', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidArgument', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidArgument', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode23 vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value %# 20110611, reported by Nils Strunk %# Make it possible to solve equations from negativ to zero, %# eg. vres = ode23 (@(t,y) y, [-2 0], 2); vdirection = sign (vtimestop - vtimestamp); %# Direction flag if (~vstepsizefixed) if (sign (vodeoptions.InitialStep) == vdirection) vstepsize = vodeoptions.InitialStep; else %# Fix wrong direction of InitialStep. vstepsize = - vodeoptions.InitialStep; end vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = vslot(1,2) - vslot(1,1); vminstepsize = sign (vstepsize) * eps; end vretvaltime = vtimestamp; %# first timestamp output vretvalresult = vinit; %# first solution output %# Initialize the OutputFcn if (vhaveoutputfunction) if (vhaveoutputselection) vretout = vretvalresult(vodeoptions.OutputSel); else vretout = vretvalresult; end feval (vodeoptions.OutputFcn, vslot.', ... vretout.', 'init', vfunarguments{:}); end %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vretvalresult.', 'init', vfunarguments{:}); end vpow = 1/3; %# 20071016, reported by Luis Randez va = [ 0, 0, 0; %# The Runge-Kutta-Fehlberg 2(3) coefficients 1/2, 0, 0; %# Coefficients proved on 20060827 -1, 2, 0]; %# See p.91 in Ascher & Petzold vb2 = [0; 1; 0]; %# 2nd and 3rd order vb3 = [1/6; 2/3; 1/6]; %# b-coefficients vc = sum (va, 2); %# The solver main loop - stop if the endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu.' * zeros(1,3); vcntiter = 0; vunhandledtermination = true; vcntsave = 2; while ((vdirection * (vtimestamp) < vdirection * (vtimestop)) && ... (vdirection * (vstepsize) >= vdirection * (vminstepsize))) %# Hit the endpoint of the time slot exactely if (vdirection * (vtimestamp + vstepsize) > vdirection * vtimestop) %# vstepsize = vtimestop - vdirection * vtimestamp; %# 20110611, reported by Nils Strunk %# The endpoint of the time slot must be hit exactly, %# eg. vsol = ode23 (@(t,y) y, [0 -1], 1); vstepsize = vdirection * abs (abs (vtimestop) - abs (vtimestamp)); end %# Estimate the three results when using this solver for j = 1:3 vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu.' + vstepsize * vk(:,1:j-1) * va(j,1:j-1).'; if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); end end %# Compute the 2nd and the 3rd order estimation y2 = vu.' + vstepsize * (vk * vb2); y3 = vu.' + vstepsize * (vk * vb3); if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y2(vodeoptions.NonNegative) = abs (y2(vodeoptions.NonNegative)); y3(vodeoptions.NonNegative) = abs (y3(vodeoptions.NonNegative)); end if (vhaveoutputfunction && vhaverefine) vSaveVUForRefine = vu; end %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizefixed) if (~vnormcontrol) vdelta = abs (y3 - y2); vtau = max (vodeoptions.RelTol * abs (vu.'), vodeoptions.AbsTol); else vdelta = norm (y3 - y2, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu.', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizefixed == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y3.'; %# MC2001: the higher order estimation as "local extrapolation" %# Save the solution every vodeoptions.OutputSave steps if (mod (vcntloop-1,vodeoptions.OutputSave) == 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; vcntsave = vcntsave + 1; end vcntloop = vcntloop + 1; vcntiter = 0; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) for vcnt = 0:vodeoptions.Refine %# Approximation between told and t if (vhaverefine) %# Do interpolation vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine.' + vapproxtime * (vk * vb3); vapproxtime = (vtimestamp - vstepsize) + vapproxtime; else vapproxvals = vu.'; vapproxtime = vtimestamp; end if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end vpltret = feval (vodeoptions.OutputFcn, vapproxtime, ... vapproxvals, [], vfunarguments{:}); if vpltret %# Leave refinement loop break; end end if (vpltret) %# Leave main loop vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu(:), [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizefixed) %# 20080425, reported by Marco Caliari %# vdelta cannot be negative (because of the absolute value that %# has been introduced) but it could be 0, then replace the zeros %# with the maximum value of vdelta vdelta(find (vdelta == 0)) = max (vdelta); %# It could happen that max (vdelta) == 0 (ie. that the original %# vdelta was 0), in that case we double the previous vstepsize vdelta(find (vdelta == 0)) = max (vtau) .* (0.4 ^ (1 / vpow)); if (vdirection == 1) vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); else vstepsize = max (- vodeoptions.MaxStep, ... max (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); end else %# if (vstepsizefixed) if (vcntloop <= vtimelength) vstepsize = vslot(vcntloop) - vslot(vcntloop-1); else %# Get out of the main integration loop break; end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for cost statistics vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vdirection * vtimestamp < vdirection * vtimestop) if (vunhandledtermination == true) error ('OdePkg:InvalidArgument', ... ['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:InvalidArgument', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vu.', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu.', 'done', vfunarguments{:}); end %# Save the last step, if not already saved if (mod (vcntloop-2,vodeoptions.OutputSave) ~= 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 3*(vcntcycles-1); %# number of ode evaluations vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d\n', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d\n', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d\n', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode23'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end end end %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference sol %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidArgument'); %! B = ode23 (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = ode23 (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = ode23 (@flor, [0 25], 1); %!test %# one output argument %! vsol = ode23 (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode23'); %!test %# two output arguments %! [vt, vy] = ode23 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode23 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = ode23 (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed through %! vsol = ode23 (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode23 (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %!test %# Solve vdp in fixed step sizes %! vsol = ode23 (@fpol, [0:0.1:2], [2 0]); %! assert (vsol.x(:), [0:0.1:2]'); %! assert (vsol.y(end,:), fref, 1e-3); %!test %# Solve in backward direction starting at t=0 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode23 (@fpol, [0 -2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve in backward direction starting at t=2 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode23 (@fpol, [2 -2], fref); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve another anonymous function in backward direction %! vref = [-1, 0.367879437558975]; %! vsol = ode23 (@(t,y) y, [0 -1], 1); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# Solve another anonymous function below zero %! vref = [0, 14.77810590694212]; %! vsol = ode23 (@(t,y) y, [-2 0], 2); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, 2, 0], 1e-1); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %!test %# Details of OutputSave can't be tested %! vopt = odeset ('OutputSave', 1, 'OutputSel', 1); %! vsla = ode23 (@fpol, [0 2], [2 0], vopt); %! vopt = odeset ('OutputSave', 2); %! vslb = ode23 (@fpol, [0 2], [2 0], vopt); %! assert (length (vsla.x) > length (vslb.x)) %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode23 (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode23 (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode23 (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie, [2; 1; 2; 1]); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode23 (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-3); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode23 (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-3); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode23 (@fpol, [0 2], [2 0], vopt); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidArgument'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/ode23d.m0000644000176000010400000010363011742512661015431 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode23d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode23d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode23d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (2,3). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# In other words, this function will solve a problem of the form %# @example %# dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) %# y(slot(1)) = init %# y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} %# @end example %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example: %# @itemize @minus %# @item %# the following code solves an anonymous implementation of a chaotic behavior %# %# @example %# fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; %# %# vopt = odeset ("NormControl", "on", "RelTol", 1e-3); %# vsol = ode23d (fcao, [0, 100], 0.5, 2, 0.5, vopt); %# %# vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); %# plot (vsol.y, vlag); legend ("fcao (t,y,z)"); %# @end example %# %# @item %# to solve the following problem with two delayed state variables %# %# @example %# d y1(t)/dt = -y1(t) %# d y2(t)/dt = -y2(t) + y1(t-5) %# d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) %# @end example %# %# one might do the following %# %# @example %# function f = fun (t, y, yd) %# f(1) = -y(1); %% y1' = -y1(t) %# f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) %# f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) %# endfunction %# T = [0,20] %# res = ode23d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); %# @end example %# %# @end itemize %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = ode23d (vfun, vslot, vinit, vlags, vhist, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode23d'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 5) print_usage; elseif (~isa (vfun, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (~isvector (vlags) || ~isnumeric (vlags)) error ('OdePkg:InvalidArgument', ... 'Fourth input argument must be a valid numerical value'); elseif ~(isnumeric (vhist) || isa (vhist, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'Fifth input argument must either be numeric or a function handle'); elseif (nargin >= 6) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode23d'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode23d'); vfunarguments = {}; end else %# if (nargin == 5) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options have been set in %# vodeoptions. Check if an invalid or unused option has been set and %# print warnings. vslot = vslot(:)'; %# Create a row vector vinit = vinit(:)'; %# Create a row vector vlags = vlags(:)'; %# Create a row vector %# Check if the user has given fixed points of time if (length (vslot) > 2), vstepsizegiven = true; %# Step size checking else vstepsizegiven = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizegiven) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); %# This implementation has been added to odepkg_structure_check.m %# elseif (~isscalar (vodeoptions.RelTol) && ~vstepsizegiven) %# error ('OdePkg:InvalidOption', ... %# 'Option "RelTol" must be set to a scalar value for this solver'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizegiven) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else %# create column vector vodeoptions.AbsTol = vodeoptions.AbsTol(:); end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')), vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidOption', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (isequal (vodeoptions.Refine, vodetemp.Refine)), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizegiven) vodeoptions.InitialStep = abs (vslot(1,1) - vslot(1,2)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizegiven) vodeoptions.MaxStep = abs (vslot(1,1) - vslot(1,length (vslot))) / 10; %# vodeoptions.MaxStep = vodeoptions.MaxStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidOption', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidOption', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidOption', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidOption', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidOption', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidOption', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidOption', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidOption', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode23d vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value if (~vstepsizegiven) vstepsize = vodeoptions.InitialStep; vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = abs (vslot(1,1) - vslot(1,2)); vminstepsize = eps; %# vslot(1,2) - vslot(1,1) - eps; end vretvaltime = vtimestamp; %# first timestamp output if (vhaveoutputselection) %# first solution output vretvalresult = vinit(vodeoptions.OutputSel); else vretvalresult = vinit; end %# Initialize the OutputFcn if (vhaveoutputfunction) feval (vodeoptions.OutputFcn, vslot', ... vretvalresult', 'init', vfunarguments{:}); end %# Initialize the History if (isnumeric (vhist)) vhmat = vhist; vhavehistnumeric = true; else %# it must be a function handle for vcnt = 1:length (vlags); vhmat(:,vcnt) = feval (vhist, (vslot(1)-vlags(vcnt)), vfunarguments{:}); end vhavehistnumeric = false; end %# Initialize DDE variables for history calculation vsaveddetime = [vtimestamp - vlags, vtimestamp]'; vsaveddeinput = [vhmat, vinit']'; vsavedderesult = [vhmat, vinit']'; %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult', vhmat}, 'init', vfunarguments{:}); end vpow = 1/3; %# 20071016, reported by Luis Randez va = [ 0, 0, 0; %# The Runge-Kutta-Fehlberg 2(3) coefficients 1/2, 0, 0; %# Coefficients proved on 20060827 -1, 2, 0]; %# See p.91 in Ascher & Petzold vb2 = [0; 1; 0]; %# 2nd and 3rd order vb3 = [1/6; 2/3; 1/6]; %# b-coefficients vc = sum (va, 2); %# The solver main loop - stop if the endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu' * zeros(1,3); vcntiter = 0; vunhandledtermination = true; while ((vtimestamp < vtimestop && vstepsize >= vminstepsize)) %# Hit the endpoint of the time slot exactely if ((vtimestamp + vstepsize) > vtimestop) vstepsize = vtimestop - vtimestamp; end %# Estimate the three results when using this solver for j = 1:3 vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu' + vstepsize * vk(:,1:j-1) * va(j,1:j-1)'; %# Claculate the history values (or get them from an external %# function) that are needed for the next step of solving if (vhavehistnumeric) for vcnt = 1:length (vlags) %# Direct implementation of a 'quadrature cubic Hermite interpolation' %# found at the Faculty for Mathematics of the University of Stuttgart %# http://mo.mathematik.uni-stuttgart.de/inhalt/aussage/aussage1269 vnumb = find (vthetime - vlags(vcnt) >= vsaveddetime); velem = min (vnumb(end), length (vsaveddetime) - 1); vstep = vsaveddetime(velem+1) - vsaveddetime(velem); vdiff = (vthetime - vlags(vcnt) - vsaveddetime(velem)) / vstep; vsubs = 1 - vdiff; %# Calculation of the coefficients for the interpolation algorithm vua = (1 + 2 * vdiff) * vsubs^2; vub = (3 - 2 * vdiff) * vdiff^2; vva = vstep * vdiff * vsubs^2; vvb = -vstep * vsubs * vdiff^2; vhmat(:,vcnt) = vua * vsaveddeinput(velem,:)' + ... vub * vsaveddeinput(velem+1,:)' + ... vva * vsavedderesult(velem,:)' + ... vvb * vsavedderesult(velem+1,:)'; end else %# the history must be a function handle for vcnt = 1:length (vlags) vhmat(:,vcnt) = feval ... (vhist, vthetime - vlags(vcnt), vfunarguments{:}); end end if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); end end %# Compute the 2nd and the 3rd order estimation y2 = vu' + vstepsize * (vk * vb2); y3 = vu' + vstepsize * (vk * vb3); if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y2(vodeoptions.NonNegative) = abs (y2(vodeoptions.NonNegative)); y3(vodeoptions.NonNegative) = abs (y3(vodeoptions.NonNegative)); end vSaveVUForRefine = vu; %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizegiven) if (~vnormcontrol) vdelta = y3 - y2; vtau = max (vodeoptions.RelTol * vu', vodeoptions.AbsTol); else vdelta = norm (y3 - y2, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizegiven == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y3'; %# MC2001: the higher order estimation as "local extrapolation" vretvaltime(vcntloop,:) = vtimestamp; if (vhaveoutputselection) vretvalresult(vcntloop,:) = vu(vodeoptions.OutputSel); else vretvalresult(vcntloop,:) = vu; end vcntloop = vcntloop + 1; vcntiter = 0; %# Update DDE values for next history calculation vsaveddetime(end+1) = vtimestamp; vsaveddeinput(end+1,:) = vtheinput'; vsavedderesult(end+1,:) = vu; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) if (vhaverefine) %# Do interpolation for vcnt = 0:vodeoptions.Refine %# Approximation between told and t vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine' + vapproxtime * (vk * vb3); if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end feval (vodeoptions.OutputFcn, (vtimestamp - vstepsize) + vapproxtime, ... vapproxvals, [], vfunarguments{:}); end end vpltret = feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', [], vfunarguments{:}); if (vpltret), vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vu(:), vhmat}, [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizegiven) %# vdelta may be 0 or even negative - could be an iteration problem vdelta = max (vdelta, eps); vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); elseif (vstepsizegiven) if (vcntloop < vtimelength) vstepsize = vslot(1,vcntloop-1) - vslot(1,vcntloop-2); end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for postprocessing vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vtimestamp < vtimestop) if (vunhandledtermination == true) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:HideWarning', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult(vcntloop-1,:), vhmat}, 'done', vfunarguments{:}); end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 3*(vcntcycles-1); %# number of ode evaluations vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode23d'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end %# else nothing will be returned, varargout{1} undefined end %! # We are using a "pseudo-DDE" implementation for all tests that %! # are done for this function. We also define an Events and a %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn. %!function [vyd] = fexp (vt, vy, vz, varargin) %! vyd(1,1) = exp (- vt) - vz(1); %# The DDEs that are %! vyd(2,1) = vy(1) - vz(2); %# used for all examples %!function [vval, vtrm, vdir] = feve (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = zeros (2,1); %# don't stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vval, vtrm, vdir] = fevn (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = ones (2,1); %# stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vmas] = fmas (vt, vy, vz, varargin) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy, vz, varargin) %! vmas = sparse ([1, 0; 0, 1]); %# A dummy sparse matrix %!function [vref] = fref () %# The reference solution %! vref = [0.12194462133618, 0.01652432423938]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = ode23d (1, [0 5], [1; 0], 1, [1; 0]); %!error %# input argument number two %! B = ode23d (@fexp, 1, [1; 0], 1, [1; 0]); %!error %# input argument number three %! B = ode23d (@fexp, [0 5], 1, 1, [1; 0]); %!error %# input argument number four %! B = ode23d (@fexp, [0 5], [1; 0], [1; 1], [1; 0]); %!error %# input argument number five %! B = ode23d (@fexp, [0 5], [1; 0], 1, 1); %!test %# one output argument %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode23d'); %!test %# two output arguments %! [vt, vy] = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 1e-1); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 1e-1); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! faym = @(vt, vy, vz) [exp(-vt) - vz(1); vy(1) - vz(2)]; %! vsol = ode23d (faym, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# extra input arguments passed trhough %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-7, 'RelTol', 1e-7); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# RelTol and NormControl option %! vopt = odeset ('AbsTol', 1e-7, 'NormControl', 'on'); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], .5e-1); %!test %# NonNegative for second component %! vopt = odeset ('NonNegative', 1); %! vsol = ode23d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2.5, 0.001, 0.237], 1e-1); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode23d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode23d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie, [1; 1]); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vie, vxe, vye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 1e-1); %! %! %# test for Jacobian option is missing %! %# test for Jacobian (being a sparse matrix) is missing %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode23d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vt(end), vy(end,:)], [5, fref], 0.5); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidOption'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/ode23s.m0000644000176000010400000002201712107217333015441 0ustar marcoAdministrators## Copyright (C) 2012 Davide Prandi ## Copyright (C) 2012 Carlo de Falco ## ## This file is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This file is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this file. If not, see ## -*- texinfo -*- ## @deftypefn{Function File} {[@var{tout}, @var{xout}] =} ode23s (@var{FUN}, @var{tspan}, @var{x0}, @var{options}) ## ## This function can be used to solve a set of stiff ordinary differential ## equations with a Rosenbrock method of order (2,3). ## ## All the mathematical formulas are from ## "The MATLAB ode suite", L.F. Shampine, M.W. Reichelt, pp.6-7 ## ## @itemize @minus ## @item @var{FUN}: String or function-handle for the problem description. ## @itemize @minus ## @item signature: @code{xprime = fun (t,x)} ## @item t: Time (scalar). ## @item x: Solution (column-vector). ## @item xprime: Returned derivative (column-vector, @code{xprime(i) = dx(i) / dt}). ## @end itemize ## @item @var{tspan}: Initial value column vector [tstart, tfinal] ## @item @var{x0}: Initial value (column-vector). ## @item @var{options}: User-defined integration parameters, using "odeset". ## See @code{help odeset} for more details. ## Option parameters currently accepted are: RelTol, MaxStep, InitialStep, Mass, Jacobian, JPattern. ## If "options" is not used, these parameters will be given default values. ## ode23s solves problems in the form M*y' = FUN (t, y), where M is a costant mass matrix, ## non-singular and possibly sparse. Set the filed @var{mass} in @var{options} using @var{odeset} ## to specify a mass matrix. ## @end itemize ## ## Example: ## @example ## f=@@(t,y) [y(2); 1000*(1-y(1)^2)*y(2)-y(1)]; ## opt = odeset ('Mass', [1 0; 0 1], 'MaxStep', 1e-1); ## [vt, vy] = ode23s (f, [0 2000], [2 0], opt); ## @end example ## ## The structure of the code is based on "ode23.m", written by Marc Compere. ## @seealso{ode23, odepkg, odeset, daspk, dassl} ## @end deftypefn % Author: Davide Prandi % Created: 5 September 2012 function [tout, xout] = ode23s (FUN, tspan, x0, options) if nargin < 4, options = odeset (); end %% Initialization d = 1 / (2 + sqrt (2)); a = 1 / 2; e32 = 6 + sqrt (2); jacfun = false; jacmat = false; if (isfield (options, 'Jacobian') && ! isempty (options.Jacobian)) %user-defined Jacobian if (ischar (options.Jacobian)) jacfun = true; jac = str2fun (options.Jacobian); elseif (is_function_handle (options.Jacobian)) jacfun = true; jac = options.Jacobian; elseif (ismatrix (options.Jacobian)) jacmat = true; jac = options.Jacobian; else error ("ode23s: the jacobian should be passed as a matrix, a string or a function handle") endif endif jacpat = false; if (isfield (options, 'JPattern') && ! isempty (options.JPattern)) %user-defined Jacobian jacpat = true; [ii, jj] = options.Jacobian; pattern = sparse (ii, jj, true); endif if (isfield (options, 'RelTol') && ! isempty (options.RelTol)) %user-defined relative tolerance rtol = options.RelTol; else rtol = 1.0e-3; endif if (isfield (options, 'AbsTol') && ! isempty (options.AbsTol)) %user-defined absolute tolerance atol = options.AbsTol; else atol = 1.0e-6; endif t = tspan(1); tfinal = tspan(2); if (isfield (options, 'MaxStep') && ! isempty (options.MaxStep)) %user-defined max step size hmax = options.MaxStep; else hmax = .1 * abs (tfinal - t); endif if (isfield (options, 'InitialStep') && ! isempty (options.InitialStep)) %user-defined initial step size h = options.InitialStep else h = (tfinal - t) * .05; % initial guess at a step size end hmin = min (16 * eps (tfinal - t), h); x = x0(:); % this always creates a column vector, x tout = t; % first output time xout = x.'; % first output solution %% The main loop while (t < tfinal) && (h >= hmin) if t + h > tfinal h = tfinal - t; endif %% Jacobian matrix, dfxpdp if (jacmat) J = jac; elseif (jacfun) J = jac (t, x); elseif (! jacpat) J = __dfxpdp__ (x, @(a) feval (FUN, t, a), rtol); elseif (jacpat) J = __dfxpdp__ (x, @(a) feval (FUN, t, a), rtol, pattern); endif T = (feval (FUN, t + .1 * h, x) - feval (FUN, t, x)) / (.1 * h); %% Wolfbrandt coefficient W = eye (length (x0))- h*d*J; %% compute the slopes F(:,1) = feval (FUN, t, x); k(:,1) = W \ (F(:,1) + h*d*T); F(:,2) = feval (FUN, t+a*h, x+a*h*k(:,1)); k(:,2) = W \ ((F(:,2) - k(:,1))) + k(:,1); %% compute the 2nd order estimate x2 = x + h*k(:,2); %% 3rd order, needed in error forumula F(:,3) = feval (FUN, t+h, x2); k(:,3) = W \ (F(:,3) - e32 * (k(:,2)-F(:,2)) - 2 * (k(:,1)-F(:,1)) + h*d*T); %% estimate the error err = (h/6) * (k(:,1) - 2*k(:,2) + k(:,3)); %% Estimate the acceptable error tau = max (rtol .* abs (x), atol); %% Update the solution only if the error is acceptable if all (err <= tau) t = t + h; tout = [tout; t]; x = x2; %no local extrapolation, FSAL (See documentation) if (isfield (options', "Mass") && ! (isempty (options.Mass))) %%user-defined mass matrix M = options.Mass; xout = [xout; (M \ x).']; else xout = [xout; x.']; end %% Update the step size if (err == 0.0) err = 1e-16; endif h = min (hmax, h*1.25); % adaptive step update else if (h <= hmin) error ("ode23s: requested step-size too small at t = %g, h = %g, err = %g \n", t, h, err) endif h = max (hmin, h*0.5); % adaptive step update endif endwhile if (t < tfinal) error ("ode23s: requested step-size too small at t = %g, h = %g, err = %g \n", t, h, err) endif endfunction %% The following function is copied from the optim %% package of Octave-Forge %% Copyright (C) 1992-1994 Richard Shrager %% Copyright (C) 1992-1994 Arthur Jutan %% Copyright (C) 1992-1994 Ray Muzic %% Copyright (C) 2010, 2011 Olaf Till function prt = __dfxpdp__ (p, func, rtol, pattern) f = func (p)(:); m = numel (f); n = numel (p); diffp = rtol .* ones (n, 1); sparse_jac = false; if (nargin > 3 && issparse (pattern)) sparse_jac = true; endif %% initialise Jacobian to Zero if (sparse_jac) prt = pattern; else prt = zeros (m, n); endif del = ifelse (p == 0, diffp, diffp .* p); absdel = abs (del); p2 = p1 = zeros (n, 1); %% double sided interval p1 = p + absdel/2; p2 = p - absdel/2; ps = p; if (! sparse_jac) for j = 1:n ps(j) = p1(j); tp1 = func (ps); ps(j) = p2(j); tp2 = func (ps); prt(:, j) = (tp1(:) - tp2(:)) / absdel(j); ps(j) = p(j); endfor else for j = find (any (pattern, 1)) ps(j) = p1(j); tp1 = func (ps); ps(j) = p2(j); tp2 = func (ps); nnz = find (pattern(:, j)); prt(nnz, j) = (tp1(nnz) - tp2(nnz)) / absdel(j); ps(j) = p(j); endfor endif endfunction %!test %! test1=@(t,y) t - y + 1; %! [vt, vy] = ode23s (test1, [0 10], [1]); %! assert ([vt(end), vy(end)], [10, exp(-10) + 10], 1e-3); %!demo %! # Demo function: stiff Van Der Pol equation %! fun = @(t,y) [y(2); 10*(1-y(1)^2)*y(2)-y(1)]; %! # Calling ode23s method %! tic () %! [vt, vy] = ode23s (fun, [0 20], [2 0]); %! toc () %! # Plotting the result %! plot(vt,vy(:,1),'-o'); %!demo %! # Demo function: stiff Van Der Pol equation %! fun = @(t,y) [y(2); 10*(1-y(1)^2)*y(2)-y(1)]; %! # Calling ode23s method %! options = odeset ("Jacobian", @(t,y) [0 1; -20*y(1)*y(2)-1, 10*(1-y(1)^2)], %! "InitialStep", 1e-3) %! tic () %! [vt, vy] = ode23s (fun, [0 20], [2 0], options); %! toc () %! # Plotting the result %! plot(vt,vy(:,1),'-o'); %!demo %! # Demo function: stiff Van Der Pol equation %! fun = @(t,y) [y(2); 100*(1-y(1)^2)*y(2)-y(1)]; %! # Calling ode23s method %! %! options = odeset ("InitialStep", 1e-4); %! tic () %! [vt, vy] = ode23s (fun, [0 200], [2 0]); %! toc () %! # Plotting the result %! plot(vt,vy(:,1),'-o'); %!demo %! # Demo function: stiff Van Der Pol equation %! fun = @(t,y) [y(2); 100*(1-y(1)^2)*y(2)-y(1)]; %! # Calling ode23s method %! options = odeset ("Jacobian", @(t,y) [0 1; -200*y(1)*y(2)-1, 100*(1-y(1)^2)], %! "InitialStep", 1e-4); %! tic () %! [vt, vy] = ode23s (fun, [0 200], [2 0], options); %! toc () %! # Plotting the result %! plot(vt,vy(:,1),'-o'); odepkg/inst/ode45.m0000644000176000010400000010330311742512661015266 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode45 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode45 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode45 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (4,5). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example, solve an anonymous implementation of the Van der Pol equation %# %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# %# vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ %# "NormControl", "on", "OutputFcn", @@odeplot); %# ode45 (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} %# ChangeLog: %# 20010703 the function file "ode45.m" was written by Marc Compere %# under the GPL for the use with this software. This function has been %# taken as a base for the following implementation. %# 20060810, Thomas Treichl %# This function was adapted to the new syntax that is used by the %# new OdePkg for Octave and is compatible to Matlab's ode45. function [varargout] = ode45 (vfun, vslot, vinit, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode45'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 3) print_usage; elseif ~(isa (vfun, 'function_handle') || isa (vfun, 'inline')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (nargin >= 4) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode45'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode45'); vfunarguments = {}; end else %# if (nargin == 3) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options are set in %# vodeoptions, check if an invalid or unused option is set vslot = vslot(:).'; %# Create a row vector vinit = vinit(:).'; %# Create a row vector if (length (vslot) > 2) %# Step size checking vstepsizefixed = true; else vstepsizefixed = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizefixed) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizefixed) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else vodeoptions.AbsTol = vodeoptions.AbsTol(:); %# Create column vector end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')) vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidArgument', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option OutputSave has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputSave)), vodeoptions.OutputSave = 1; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (vodeoptions.Refine > 0), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizefixed) vodeoptions.InitialStep = (vslot(1,2) - vslot(1,1)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidArgument', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizefixed) vodeoptions.MaxStep = abs (vslot(1,2) - vslot(1,1)) / 10; warning ('OdePkg:InvalidArgument', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidArgument', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidArgument', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidArgument', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidArgument', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidArgument', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode45 vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value %# 20110611, reported by Nils Strunk %# Make it possible to solve equations from negativ to zero, %# eg. vres = ode45 (@(t,y) y, [-2 0], 2); vdirection = sign (vtimestop - vtimestamp); %# Direction flag if (~vstepsizefixed) if (sign (vodeoptions.InitialStep) == vdirection) vstepsize = vodeoptions.InitialStep; else %# Fix wrong direction of InitialStep. vstepsize = - vodeoptions.InitialStep; end vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = vslot(1,2) - vslot(1,1); vminstepsize = sign (vstepsize) * eps; end vretvaltime = vtimestamp; %# first timestamp output vretvalresult = vinit; %# first solution output %# Initialize the OutputFcn if (vhaveoutputfunction) if (vhaveoutputselection) vretout = vretvalresult(vodeoptions.OutputSel); else vretout = vretvalresult; end feval (vodeoptions.OutputFcn, vslot.', ... vretout.', 'init', vfunarguments{:}); end %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vretvalresult.', 'init', vfunarguments{:}); end vpow = 1/5; %# 20071016, reported by Luis Randez va = [0, 0, 0, 0, 0; %# The Runge-Kutta-Fehlberg 4(5) coefficients 1/4, 0, 0, 0, 0; %# Coefficients proved on 20060827 3/32, 9/32, 0, 0, 0; %# See p.91 in Ascher & Petzold 1932/2197, -7200/2197, 7296/2197, 0, 0; 439/216, -8, 3680/513, -845/4104, 0; -8/27, 2, -3544/2565, 1859/4104, -11/40]; %# 4th and 5th order b-coefficients vb4 = [25/216; 0; 1408/2565; 2197/4104; -1/5; 0]; vb5 = [16/135; 0; 6656/12825; 28561/56430; -9/50; 2/55]; vc = sum (va, 2); %# The solver main loop - stop if the endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu.' * zeros(1,6); vcntiter = 0; vunhandledtermination = true; vcntsave = 2; while ((vdirection * (vtimestamp) < vdirection * (vtimestop)) && ... (vdirection * (vstepsize) >= vdirection * (vminstepsize))) %# Hit the endpoint of the time slot exactely if (vdirection * (vtimestamp + vstepsize) > vdirection * vtimestop) %# vstepsize = vtimestop - vdirection * vtimestamp; %# 20110611, reported by Nils Strunk %# The endpoint of the time slot must be hit exactly, %# eg. vsol = ode45 (@(t,y) y, [0 -1], 1); vstepsize = vdirection * abs (abs (vtimestop) - abs (vtimestamp)); end %# Estimate the six results when using this solver for j = 1:6 vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu.' + vstepsize * vk(:,1:j-1) * va(j,1:j-1).'; if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); end end %# Compute the 4th and the 5th order estimation y4 = vu.' + vstepsize * (vk * vb4); y5 = vu.' + vstepsize * (vk * vb5); if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y4(vodeoptions.NonNegative) = abs (y4(vodeoptions.NonNegative)); y5(vodeoptions.NonNegative) = abs (y5(vodeoptions.NonNegative)); end if (vhaveoutputfunction && vhaverefine) vSaveVUForRefine = vu; end %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizefixed) if (~vnormcontrol) vdelta = abs (y5 - y4); vtau = max (vodeoptions.RelTol * abs (vu.'), vodeoptions.AbsTol); else vdelta = norm (y5 - y4, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu.', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizefixed == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y5.'; %# MC2001: the higher order estimation as "local extrapolation" %# Save the solution every vodeoptions.OutputSave steps if (mod (vcntloop-1,vodeoptions.OutputSave) == 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; vcntsave = vcntsave + 1; end vcntloop = vcntloop + 1; vcntiter = 0; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) for vcnt = 0:vodeoptions.Refine %# Approximation between told and t if (vhaverefine) %# Do interpolation vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine.' + vapproxtime * (vk * vb5); vapproxtime = (vtimestamp - vstepsize) + vapproxtime; else vapproxvals = vu.'; vapproxtime = vtimestamp; end if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end vpltret = feval (vodeoptions.OutputFcn, vapproxtime, ... vapproxvals, [], vfunarguments{:}); if vpltret %# Leave refinement loop break; end end if (vpltret) %# Leave main loop vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu(:), [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizefixed) %# 20080425, reported by Marco Caliari %# vdelta cannot be negative (because of the absolute value that %# has been introduced) but it could be 0, then replace the zeros %# with the maximum value of vdelta vdelta(find (vdelta == 0)) = max (vdelta); %# It could happen that max (vdelta) == 0 (ie. that the original %# vdelta was 0), in that case we double the previous vstepsize vdelta(find (vdelta == 0)) = max (vtau) .* (0.4 ^ (1 / vpow)); if (vdirection == 1) vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); else vstepsize = max (- vodeoptions.MaxStep, ... max (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); end else %# if (vstepsizefixed) if (vcntloop <= vtimelength) vstepsize = vslot(vcntloop) - vslot(vcntloop-1); else %# Get out of the main integration loop break; end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for cost statistics vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vdirection * vtimestamp < vdirection * vtimestop) if (vunhandledtermination == true) error ('OdePkg:InvalidArgument', ... ['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:InvalidArgument', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vu.', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu.', 'done', vfunarguments{:}); end %# Save the last step, if not already saved if (mod (vcntloop-2,vodeoptions.OutputSave) ~= 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 6*(vcntcycles-1); %# number of ode evaluations vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d\n', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d\n', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d\n', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode45'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end end end %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference sol %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidArgument'); %! B = ode45 (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = ode45 (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = ode45 (@flor, [0 25], 1); %!test %# one output argument %! vsol = ode45 (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode45'); %!test %# two output arguments %! [vt, vy] = ode45 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode45 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = ode45 (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed through %! vsol = ode45 (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode45 (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %!test %# Solve vdp in fixed step sizes %! vsol = ode45 (@fpol, [0:0.1:2], [2 0]); %! assert (vsol.x(:), [0:0.1:2]'); %! assert (vsol.y(end,:), fref, 1e-3); %!test %# Solve in backward direction starting at t=0 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode45 (@fpol, [0 -2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve in backward direction starting at t=2 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode45 (@fpol, [2 -2], fref); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve another anonymous function in backward direction %! vref = [-1, 0.367879437558975]; %! vsol = ode45 (@(t,y) y, [0 -1], 1); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# Solve another anonymous function below zero %! vref = [0, 14.77810590694212]; %! vsol = ode45 (@(t,y) y, [-2 0], 2); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-5); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, 2, 0], 0.5); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %!test %# Details of OutputSave can't be tested %! vopt = odeset ('OutputSave', 1, 'OutputSel', 1); %! vsla = ode45 (@fpol, [0 2], [2 0], vopt); %! vopt = odeset ('OutputSave', 2); %! vslb = ode45 (@fpol, [0 2], [2 0], vopt); %! assert (length (vsla.x) > length (vslb.x)) %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode45 (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode45 (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-3); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode45 (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode45 (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], .5e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode45 (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode45 (@fpol, [0 2], [2 0], vopt); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidArgument'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/ode45d.m0000644000176000010400000010413311742512661015434 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode45d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode45d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode45d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (4,5). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# In other words, this function will solve a problem of the form %# @example %# dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) %# y(slot(1)) = init %# y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} %# @end example %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example: %# @itemize @minus %# @item %# the following code solves an anonymous implementation of a chaotic behavior %# %# @example %# fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; %# %# vopt = odeset ("NormControl", "on", "RelTol", 1e-3); %# vsol = ode45d (fcao, [0, 100], 0.5, 2, 0.5, vopt); %# %# vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); %# plot (vsol.y, vlag); legend ("fcao (t,y,z)"); %# @end example %# %# @item %# to solve the following problem with two delayed state variables %# %# @example %# d y1(t)/dt = -y1(t) %# d y2(t)/dt = -y2(t) + y1(t-5) %# d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) %# @end example %# %# one might do the following %# %# @example %# function f = fun (t, y, yd) %# f(1) = -y(1); %% y1' = -y1(t) %# f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) %# f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) %# endfunction %# T = [0,20] %# res = ode45d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); %# @end example %# %# @end itemize %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = ode45d (vfun, vslot, vinit, vlags, vhist, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode45d'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 5) print_usage; elseif (~isa (vfun, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (~isvector (vlags) || ~isnumeric (vlags)) error ('OdePkg:InvalidArgument', ... 'Fourth input argument must be a valid numerical value'); elseif ~(isnumeric (vhist) || isa (vhist, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'Fifth input argument must either be numeric or a function handle'); elseif (nargin >= 6) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode45d'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode45d'); vfunarguments = {}; end else %# if (nargin == 5) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options have been set in %# vodeoptions. Check if an invalid or unused option has been set and %# print warnings. vslot = vslot(:)'; %# Create a row vector vinit = vinit(:)'; %# Create a row vector vlags = vlags(:)'; %# Create a row vector %# Check if the user has given fixed points of time if (length (vslot) > 2), vstepsizegiven = true; %# Step size checking else vstepsizegiven = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizegiven) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); %# This implementation has been added to odepkg_structure_check.m %# elseif (~isscalar (vodeoptions.RelTol) && ~vstepsizegiven) %# error ('OdePkg:InvalidOption', ... %# 'Option "RelTol" must be set to a scalar value for this solver'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizegiven) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else %# create column vector vodeoptions.AbsTol = vodeoptions.AbsTol(:); end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')), vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidOption', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (isequal (vodeoptions.Refine, vodetemp.Refine)), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizegiven) vodeoptions.InitialStep = abs (vslot(1,1) - vslot(1,2)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizegiven) vodeoptions.MaxStep = abs (vslot(1,1) - vslot(1,length (vslot))) / 10; %# vodeoptions.MaxStep = vodeoptions.MaxStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidOption', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidOption', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidOption', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidOption', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidOption', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidOption', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidOption', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidOption', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode45d vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value if (~vstepsizegiven) vstepsize = vodeoptions.InitialStep; vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = abs (vslot(1,1) - vslot(1,2)); vminstepsize = eps; %# vslot(1,2) - vslot(1,1) - eps; end vretvaltime = vtimestamp; %# first timestamp output if (vhaveoutputselection) %# first solution output vretvalresult = vinit(vodeoptions.OutputSel); else vretvalresult = vinit; end %# Initialize the OutputFcn if (vhaveoutputfunction) feval (vodeoptions.OutputFcn, vslot', ... vretvalresult', 'init', vfunarguments{:}); end %# Initialize the History if (isnumeric (vhist)) vhmat = vhist; vhavehistnumeric = true; else %# it must be a function handle for vcnt = 1:length (vlags); vhmat(:,vcnt) = feval (vhist, (vslot(1)-vlags(vcnt)), vfunarguments{:}); end vhavehistnumeric = false; end %# Initialize DDE variables for history calculation vsaveddetime = [vtimestamp - vlags, vtimestamp]'; vsaveddeinput = [vhmat, vinit']'; vsavedderesult = [vhmat, vinit']'; %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult', vhmat}, 'init', vfunarguments{:}); end vpow = 1/5; %# 20071016, reported by Luis Randez va = [0, 0, 0, 0, 0; %# The Runge-Kutta-Fehlberg 4(5) coefficients 1/4, 0, 0, 0, 0; %# Coefficients proved on 20060827 3/32, 9/32, 0, 0, 0; %# See p.91 in Ascher & Petzold 1932/2197, -7200/2197, 7296/2197, 0, 0; 439/216, -8, 3680/513, -845/4104, 0; -8/27, 2, -3544/2565, 1859/4104, -11/40]; %# 4th and 5th order b-coefficients vb4 = [25/216; 0; 1408/2565; 2197/4104; -1/5; 0]; vb5 = [16/135; 0; 6656/12825; 28561/56430; -9/50; 2/55]; vc = sum (va, 2); %# The solver main loop - stop if endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu' * zeros(1,6); vcntiter = 0; vunhandledtermination = true; while ((vtimestamp < vtimestop && vstepsize >= vminstepsize)) %# Hit the endpoint of the time slot exactely if ((vtimestamp + vstepsize) > vtimestop) vstepsize = vtimestop - vtimestamp; end %# Estimate the six results when using this solver for j = 1:6 vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu' + vstepsize * vk(:,1:j-1) * va(j,1:j-1)'; %# Claculate the history values (or get them from an external %# function) that are needed for the next step of solving if (vhavehistnumeric) for vcnt = 1:length (vlags) %# Direct implementation of a 'quadrature cubic Hermite interpolation' %# found at the Faculty for Mathematics of the University of Stuttgart %# http://mo.mathematik.uni-stuttgart.de/inhalt/aussage/aussage1269 vnumb = find (vthetime - vlags(vcnt) >= vsaveddetime); velem = min (vnumb(end), length (vsaveddetime) - 1); vstep = vsaveddetime(velem+1) - vsaveddetime(velem); vdiff = (vthetime - vlags(vcnt) - vsaveddetime(velem)) / vstep; vsubs = 1 - vdiff; %# Calculation of the coefficients for the interpolation algorithm vua = (1 + 2 * vdiff) * vsubs^2; vub = (3 - 2 * vdiff) * vdiff^2; vva = vstep * vdiff * vsubs^2; vvb = -vstep * vsubs * vdiff^2; vhmat(:,vcnt) = vua * vsaveddeinput(velem,:)' + ... vub * vsaveddeinput(velem+1,:)' + ... vva * vsavedderesult(velem,:)' + ... vvb * vsavedderesult(velem+1,:)'; end else %# the history must be a function handle for vcnt = 1:length (vlags) vhmat(:,vcnt) = feval ... (vhist, vthetime - vlags(vcnt), vfunarguments{:}); end end if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); end end %# Compute the 4th and the 5th order estimation y4 = vu' + vstepsize * (vk * vb4); y5 = vu' + vstepsize * (vk * vb5); if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y4(vodeoptions.NonNegative) = abs (y4(vodeoptions.NonNegative)); y5(vodeoptions.NonNegative) = abs (y5(vodeoptions.NonNegative)); end vSaveVUForRefine = vu; %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizegiven) if (~vnormcontrol) vdelta = y5 - y4; vtau = max (vodeoptions.RelTol * vu', vodeoptions.AbsTol); else vdelta = norm (y5 - y4, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizegiven == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y5'; %# MC2001: the higher order estimation as "local extrapolation" vretvaltime(vcntloop,:) = vtimestamp; if (vhaveoutputselection) vretvalresult(vcntloop,:) = vu(vodeoptions.OutputSel); else vretvalresult(vcntloop,:) = vu; end vcntloop = vcntloop + 1; vcntiter = 0; %# Update DDE values for next history calculation vsaveddetime(end+1) = vtimestamp; vsaveddeinput(end+1,:) = vtheinput'; vsavedderesult(end+1,:) = vu; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) if (vhaverefine) %# Do interpolation for vcnt = 0:vodeoptions.Refine %# Approximation between told and t vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine' + vapproxtime * (vk * vb5); if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end feval (vodeoptions.OutputFcn, (vtimestamp - vstepsize) + vapproxtime, ... vapproxvals, [], vfunarguments{:}); end end vpltret = feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', [], vfunarguments{:}); if (vpltret), vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vu(:), vhmat}, [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizegiven) %# vdelta may be 0 or even negative - could be an iteration problem vdelta = max (vdelta, eps); vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); elseif (vstepsizegiven) if (vcntloop < vtimelength) vstepsize = vslot(1,vcntloop-1) - vslot(1,vcntloop-2); end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for postprocessing vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vtimestamp < vtimestop) if (vunhandledtermination == true) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:HideWarning', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult(vcntloop-1,:), vhmat}, 'done', vfunarguments{:}); end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 6*(vcntcycles-1); %# number of ode evaluations vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode45d'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end %# else nothing will be returned, varargout{1} undefined end %! # We are using a "pseudo-DDE" implementation for all tests that %! # are done for this function. We also define an Events and a %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn. %!function [vyd] = fexp (vt, vy, vz, varargin) %! vyd(1,1) = exp (- vt) - vz(1); %# The DDEs that are %! vyd(2,1) = vy(1) - vz(2); %# used for all examples %!function [vval, vtrm, vdir] = feve (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = zeros (2,1); %# don't stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vval, vtrm, vdir] = fevn (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = ones (2,1); %# stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vmas] = fmas (vt, vy, vz, varargin) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy, vz, varargin) %! vmas = sparse ([1, 0; 0, 1]); %# A dummy sparse matrix %!function [vref] = fref () %# The reference solution %! vref = [0.12194462133618, 0.01652432423938]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = ode45d (1, [0 5], [1; 0], 1, [1; 0]); %!error %# input argument number two %! B = ode45d (@fexp, 1, [1; 0], 1, [1; 0]); %!error %# input argument number three %! B = ode45d (@fexp, [0 5], 1, 1, [1; 0]); %!error %# input argument number four %! B = ode45d (@fexp, [0 5], [1; 0], [1; 1], [1; 0]); %!error %# input argument number five %! B = ode45d (@fexp, [0 5], [1; 0], 1, 1); %!test %# one output argument %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode45d'); %!test %# two output arguments %! [vt, vy] = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 0.5); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 0.5); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! faym = @(vt, vy, vz) [exp(-vt) - vz(1); vy(1) - vz(2)]; %! vsol = ode45d (faym, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# extra input arguments passed trhough %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-7, 'RelTol', 1e-7); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# RelTol and NormControl option %! vopt = odeset ('AbsTol', 1e-7, 'NormControl', 'on'); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], .5e-1); %!test %# NonNegative for second component %! vopt = odeset ('NonNegative', 1); %! vsol = ode45d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2.5, 0.001, 0.237], 0.5); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode45d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode45d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie, [1; 1]); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 0.5); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vie, vxe, vye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 0.5); %! %! %# test for Jacobian option is missing %! %# test for Jacobian (being a sparse matrix) is missing %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.5); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode45d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vt(end), vy(end,:)], [5, fref], 0.5); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidOption'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/ode54.m0000644000176000010400000010645111742512661015275 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode54 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode54 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode54 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (5,4). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example, solve an anonymous implementation of the Van der Pol equation %# %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# %# vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ %# "NormControl", "on", "OutputFcn", @@odeplot); %# ode54 (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} %# ChangeLog: %# 20010703 the function file "ode54.m" was written by Marc Compere %# under the GPL for the use with this software. This function has been %# taken as a base for the following implementation. %# 20060810, Thomas Treichl %# This function was adapted to the new syntax that is used by the %# new OdePkg for Octave. An equivalent function in Matlab does not %# exist. function [varargout] = ode54 (vfun, vslot, vinit, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode54'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 3) print_usage; elseif ~(isa (vfun, 'function_handle') || isa (vfun, 'inline')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (nargin >= 4) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode54'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode54'); vfunarguments = {}; end else %# if (nargin == 3) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options are set in %# vodeoptions, check if an invalid or unused option is set vslot = vslot(:).'; %# Create a row vector vinit = vinit(:).'; %# Create a row vector if (length (vslot) > 2) %# Step size checking vstepsizefixed = true; else vstepsizefixed = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizefixed) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizefixed) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else vodeoptions.AbsTol = vodeoptions.AbsTol(:); %# Create column vector end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')) vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidArgument', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option OutputSave has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputSave)), vodeoptions.OutputSave = 1; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (vodeoptions.Refine > 0), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizefixed) vodeoptions.InitialStep = (vslot(1,2) - vslot(1,1)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidArgument', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizefixed) vodeoptions.MaxStep = abs (vslot(1,2) - vslot(1,1)) / 10; warning ('OdePkg:InvalidArgument', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidArgument', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidArgument', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidArgument', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidArgument', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidArgument', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode54 vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value %# 20110611, reported by Nils Strunk %# Make it possible to solve equations from negativ to zero, %# eg. vres = ode54 (@(t,y) y, [-2 0], 2); vdirection = sign (vtimestop - vtimestamp); %# Direction flag if (~vstepsizefixed) if (sign (vodeoptions.InitialStep) == vdirection) vstepsize = vodeoptions.InitialStep; else %# Fix wrong direction of InitialStep. vstepsize = - vodeoptions.InitialStep; end vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = vslot(1,2) - vslot(1,1); vminstepsize = sign (vstepsize) * eps; end vretvaltime = vtimestamp; %# first timestamp output vretvalresult = vinit; %# first solution output %# Initialize the OutputFcn if (vhaveoutputfunction) if (vhaveoutputselection) vretout = vretvalresult(vodeoptions.OutputSel); else vretout = vretvalresult; end feval (vodeoptions.OutputFcn, vslot.', ... vretout.', 'init', vfunarguments{:}); end %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vretvalresult.', 'init', vfunarguments{:}); end vpow = 1/5; %# 20071016, reported by Luis Randez va = [0, 0, 0, 0, 0, 0; %# The Dormand-Prince 5(4) coefficients 1/5, 0, 0, 0, 0, 0; %# Coefficients proved on 20060827 3/40, 9/40, 0, 0, 0, 0; %# See p.91 in Ascher & Petzold 44/45, -56/15, 32/9, 0, 0, 0; 19372/6561, -25360/2187, 64448/6561, -212/729, 0, 0; 9017/3168, -355/33, 46732/5247, 49/176, -5103/18656, 0; 35/384, 0, 500/1113, 125/192, -2187/6784, 11/84]; %# 4th and 5th order b-coefficients vb4 = [5179/57600; 0; 7571/16695; 393/640; -92097/339200; 187/2100; 1/40]; vb5 = [35/384; 0; 500/1113; 125/192; -2187/6784; 11/84; 0]; vc = sum (va, 2); %# The solver main loop - stop if the endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu.' * zeros(1,7); vcntiter = 0; vunhandledtermination = true; vcntsave = 2; %# FSAL optimizations: sent by Bruce Minaker 20110326, find the slope k1 %# (k1 is copied from last k7, so set k7) for first time step only if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vtimestamp, vinit.', vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vtimestamp, vfunarguments{:}); end vk(:,7) = vmass \ feval ... (vfun, vtimestamp, vinit.', vfunarguments{:}); else vk(:,7) = feval ... (vfun, vtimestamp, vinit.', vfunarguments{:}); end while ((vdirection * (vtimestamp) < vdirection * (vtimestop)) && ... (vdirection * (vstepsize) >= vdirection * (vminstepsize))) %# Hit the endpoint of the time slot exactely if (vdirection * (vtimestamp + vstepsize) > vdirection * vtimestop) %# vstepsize = vtimestop - vdirection * vtimestamp; %# 20110611, reported by Nils Strunk %# The endpoint of the time slot must be hit exactly, %# eg. vsol = ode54 (@(t,y) y, [0 -1], 1); vstepsize = vdirection * abs (abs (vtimestop) - abs (vtimestamp)); end %# Estimate the seven results when using this solver (FSAL) %# skip the first result as we already know it from last time step vk(:,1)=vk(:,7); for j = 2:7 %# Start at two instead of one (FSAL) vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu.' + vstepsize * vk(:,1:j-1) * va(j,1:j-1).'; if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); end end %# Compute the 4th and the 5th order estimation y4 = vu.' + vstepsize * (vk * vb4); y5 = vtheinput; %# y5 = vu.' + vstepsize * (vk * vb5); vb5 is the same as va(6,:), %# means that we already know y5 from the first six vk's (FSAL) if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y4(vodeoptions.NonNegative) = abs (y4(vodeoptions.NonNegative)); y5(vodeoptions.NonNegative) = abs (y5(vodeoptions.NonNegative)); end if (vhaveoutputfunction && vhaverefine) vSaveVUForRefine = vu; end %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizefixed) if (~vnormcontrol) vdelta = abs (y5 - y4); vtau = max (vodeoptions.RelTol * abs (vu.'), vodeoptions.AbsTol); else vdelta = norm (y5 - y4, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu.', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizefixed == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y5.'; %# MC2001: the higher order estimation as "local extrapolation" %# Save the solution every vodeoptions.OutputSave steps if (mod (vcntloop-1,vodeoptions.OutputSave) == 0) if (vhaveoutputselection) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu(vodeoptions.OutputSel); else vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; end vcntsave = vcntsave + 1; end vcntloop = vcntloop + 1; vcntiter = 0; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) for vcnt = 0:vodeoptions.Refine %# Approximation between told and t if (vhaverefine) %# Do interpolation vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine.' + vapproxtime * (vk * vb5); vapproxtime = (vtimestamp - vstepsize) + vapproxtime; else vapproxvals = vu.'; vapproxtime = vtimestamp; end if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end vpltret = feval (vodeoptions.OutputFcn, vapproxtime, ... vapproxvals, [], vfunarguments{:}); if vpltret %# Leave refinement loop break; end end if (vpltret) %# Leave main loop vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu(:), [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end else vk(:,7) = vk(:,1); %# If we're here, then we've overwritten the k7 that we %# need to copy to k1 to redo the step Since we copy k7 %# into k1, we'll put the k1 back in k7 for now, until it's %# copied back again (FSAL) end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizefixed) %# 2008-20120425, reported by Marco Caliari %# vdelta cannot be negative (because of the absolute value that %# has been introduced) but it could be 0, then replace the zeros %# with the maximum value of vdelta vdelta(find (vdelta == 0)) = max (vdelta); %# It could happen that max (vdelta) == 0 (ie. that the original %# vdelta was 0), in that case we double the previous vstepsize vdelta(find (vdelta == 0)) = max (vtau) .* (0.4 ^ (1 / vpow)); if (vdirection == 1) vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); else vstepsize = max (- vodeoptions.MaxStep, ... max (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); end else %# if (vstepsizefixed) if (vcntloop <= vtimelength) vstepsize = vslot(vcntloop) - vslot(vcntloop-1); else %# Get out of the main integration loop break; end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for cost statistics vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vdirection * vtimestamp < vdirection * vtimestop) if (vunhandledtermination == true) error ('OdePkg:InvalidArgument', ... ['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:InvalidArgument', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vu.', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu.', 'done', vfunarguments{:}); end %# Save the last step, if not already saved if (mod (vcntloop-2,vodeoptions.OutputSave) ~= 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 6*(vcntcycles-1)+1; %# 7 stages & one first step (FSAL) vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d\n', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d\n', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d\n', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode54'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end end end %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference sol %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidArgument'); %! B = ode54 (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = ode54 (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = ode54 (@flor, [0 25], 1); %!test %# one output argument %! vsol = ode54 (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode54'); %!test %# two output arguments %! [vt, vy] = ode54 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode54 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = ode54 (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = ode54 (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode54 (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %!test %# Solve vdp in fixed step sizes %! vsol = ode54 (@fpol, [0:0.1:2], [2 0]); %! assert (vsol.x(:), [0:0.1:2]'); %! assert (vsol.y(end,:), fref, 1e-3); %!test %# Solve in backward direction starting at t=0 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode54 (@fpol, [0 -2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve in backward direction starting at t=2 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode54 (@fpol, [2 -2], fref); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve another anonymous function in backward direction %! vref = [-1, 0.367879437558975]; %! vsol = ode54 (@(t,y) y, [0 -1], 1); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# Solve another anonymous function below zero %! vref = [0, 14.77810590694212]; %! vsol = ode54 (@(t,y) y, [-2 0], 2); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-4); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, 2, 0], 1e-1); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %!test %# Details of OutputSave can't be tested %! vopt = odeset ('OutputSave', 1, 'OutputSel', 1); %! vsla = ode54 (@fpol, [0 2], [2 0], vopt); %! vopt = odeset ('OutputSave', 2); %! vslb = ode54 (@fpol, [0 2], [2 0], vopt); %! assert (length (vsla.x) > length (vslb.x)) %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode54 (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode54 (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-3); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve, 'InitialStep', 1e-6); %! vsol = ode54 (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! vopt = odeset ('Events', @fevn, 'InitialStep', 1e-6); %! vsol = ode54 (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'InitialStep', 1e-6); %! [vt, vy, vxe, vye, vie] = ode54 (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode54 (@fpol, [0 2], [2 0], vopt); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidArgument'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/ode54d.m0000644000176000010400000010434311742512661015437 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode54d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode54d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode54d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (2,3). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# In other words, this function will solve a problem of the form %# @example %# dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) %# y(slot(1)) = init %# y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} %# @end example %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example: %# @itemize @minus %# @item %# the following code solves an anonymous implementation of a chaotic behavior %# %# @example %# fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; %# %# vopt = odeset ("NormControl", "on", "RelTol", 1e-3); %# vsol = ode54d (fcao, [0, 100], 0.5, 2, 0.5, vopt); %# %# vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); %# plot (vsol.y, vlag); legend ("fcao (t,y,z)"); %# @end example %# %# @item %# to solve the following problem with two delayed state variables %# %# @example %# d y1(t)/dt = -y1(t) %# d y2(t)/dt = -y2(t) + y1(t-5) %# d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) %# @end example %# %# one might do the following %# %# @example %# function f = fun (t, y, yd) %# f(1) = -y(1); %% y1' = -y1(t) %# f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) %# f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) %# endfunction %# T = [0,20] %# res = ode54d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); %# @end example %# %# @end itemize %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = ode54d (vfun, vslot, vinit, vlags, vhist, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode54d'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 5) print_usage; elseif (~isa (vfun, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (~isvector (vlags) || ~isnumeric (vlags)) error ('OdePkg:InvalidArgument', ... 'Fourth input argument must be a valid numerical value'); elseif ~(isnumeric (vhist) || isa (vhist, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'Fifth input argument must either be numeric or a function handle'); elseif (nargin >= 6) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode54d'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode54d'); vfunarguments = {}; end else %# if (nargin == 5) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options have been set in %# vodeoptions. Check if an invalid or unused option has been set and %# print warnings. vslot = vslot(:)'; %# Create a row vector vinit = vinit(:)'; %# Create a row vector vlags = vlags(:)'; %# Create a row vector %# Check if the user has given fixed points of time if (length (vslot) > 2), vstepsizegiven = true; %# Step size checking else vstepsizegiven = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizegiven) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); %# This implementation has been added to odepkg_structure_check.m %# elseif (~isscalar (vodeoptions.RelTol) && ~vstepsizegiven) %# error ('OdePkg:InvalidOption', ... %# 'Option "RelTol" must be set to a scalar value for this solver'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizegiven) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else %# create column vector vodeoptions.AbsTol = vodeoptions.AbsTol(:); end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')), vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidOption', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (isequal (vodeoptions.Refine, vodetemp.Refine)), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizegiven) vodeoptions.InitialStep = abs (vslot(1,1) - vslot(1,2)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizegiven) vodeoptions.MaxStep = abs (vslot(1,1) - vslot(1,length (vslot))) / 10; %# vodeoptions.MaxStep = vodeoptions.MaxStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidOption', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidOption', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidOption', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidOption', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidOption', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidOption', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidOption', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidOption', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode54d vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value if (~vstepsizegiven) vstepsize = vodeoptions.InitialStep; vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = abs (vslot(1,1) - vslot(1,2)); vminstepsize = eps; %# vslot(1,2) - vslot(1,1) - eps; end vretvaltime = vtimestamp; %# first timestamp output if (vhaveoutputselection) %# first solution output vretvalresult = vinit(vodeoptions.OutputSel); else vretvalresult = vinit; end %# Initialize the OutputFcn if (vhaveoutputfunction) feval (vodeoptions.OutputFcn, vslot', ... vretvalresult', 'init', vfunarguments{:}); end %# Initialize the History if (isnumeric (vhist)) vhmat = vhist; vhavehistnumeric = true; else %# it must be a function handle for vcnt = 1:length (vlags); vhmat(:,vcnt) = feval (vhist, (vslot(1)-vlags(vcnt)), vfunarguments{:}); end vhavehistnumeric = false; end %# Initialize DDE variables for history calculation vsaveddetime = [vtimestamp - vlags, vtimestamp]'; vsaveddeinput = [vhmat, vinit']'; vsavedderesult = [vhmat, vinit']'; %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult', vhmat}, 'init', vfunarguments{:}); end vpow = 1/5; %# 20071016, reported by Luis Randez va = [0, 0, 0, 0, 0, 0; %# The Dormand-Prince 5(4) coefficients 1/5, 0, 0, 0, 0, 0; %# Coefficients proved on 20060827 3/40, 9/40, 0, 0, 0, 0; %# See p.91 in Ascher & Petzold 44/45, -56/15, 32/9, 0, 0, 0; 19372/6561, -25360/2187, 64448/6561, -212/729, 0, 0; 9017/3168, -355/33, 46732/5247, 49/176, -5103/18656, 0; 35/384, 0, 500/1113, 125/192, -2187/6784, 11/84]; %# 4th and 5th order b-coefficients vb4 = [35/384; 0; 500/1113; 125/192; -2187/6784; 11/84; 0]; vb5 = [5179/57600; 0; 7571/16695; 393/640; -92097/339200; 187/2100; 1/40]; vc = sum (va, 2); %# The solver main loop - stop if the endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu' * zeros(1,7); vcntiter = 0; vunhandledtermination = true; while ((vtimestamp < vtimestop && vstepsize >= vminstepsize)) %# Hit the endpoint of the time slot exactely if ((vtimestamp + vstepsize) > vtimestop) vstepsize = vtimestop - vtimestamp; end %# Estimate the seven results when using this solver for j = 1:7 vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu' + vstepsize * vk(:,1:j-1) * va(j,1:j-1)'; %# Claculate the history values (or get them from an external %# function) that are needed for the next step of solving if (vhavehistnumeric) for vcnt = 1:length (vlags) %# Direct implementation of a 'quadrature cubic Hermite interpolation' %# found at the Faculty for Mathematics of the University of Stuttgart %# http://mo.mathematik.uni-stuttgart.de/inhalt/aussage/aussage1269 vnumb = find (vthetime - vlags(vcnt) >= vsaveddetime); velem = min (vnumb(end), length (vsaveddetime) - 1); vstep = vsaveddetime(velem+1) - vsaveddetime(velem); vdiff = (vthetime - vlags(vcnt) - vsaveddetime(velem)) / vstep; vsubs = 1 - vdiff; %# Calculation of the coefficients for the interpolation algorithm vua = (1 + 2 * vdiff) * vsubs^2; vub = (3 - 2 * vdiff) * vdiff^2; vva = vstep * vdiff * vsubs^2; vvb = -vstep * vsubs * vdiff^2; vhmat(:,vcnt) = vua * vsaveddeinput(velem,:)' + ... vub * vsaveddeinput(velem+1,:)' + ... vva * vsavedderesult(velem,:)' + ... vvb * vsavedderesult(velem+1,:)'; end else %# the history must be a function handle for vcnt = 1:length (vlags) vhmat(:,vcnt) = feval ... (vhist, vthetime - vlags(vcnt), vfunarguments{:}); end end if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); end end %# Compute the 4th and the 5th order estimation y4 = vu' + vstepsize * (vk * vb4); y5 = vu' + vstepsize * (vk * vb5); if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y4(vodeoptions.NonNegative) = abs (y4(vodeoptions.NonNegative)); y5(vodeoptions.NonNegative) = abs (y5(vodeoptions.NonNegative)); end vSaveVUForRefine = vu; %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizegiven) if (~vnormcontrol) vdelta = y5 - y4; vtau = max (vodeoptions.RelTol * vu', vodeoptions.AbsTol); else vdelta = norm (y5 - y4, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizegiven == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y5'; %# MC2001: the higher order estimation as "local extrapolation" vretvaltime(vcntloop,:) = vtimestamp; if (vhaveoutputselection) vretvalresult(vcntloop,:) = vu(vodeoptions.OutputSel); else vretvalresult(vcntloop,:) = vu; end vcntloop = vcntloop + 1; vcntiter = 0; %# Update DDE values for next history calculation vsaveddetime(end+1) = vtimestamp; vsaveddeinput(end+1,:) = vtheinput'; vsavedderesult(end+1,:) = vu; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) if (vhaverefine) %# Do interpolation for vcnt = 0:vodeoptions.Refine %# Approximation between told and t vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine' + vapproxtime * (vk * vb5); if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end feval (vodeoptions.OutputFcn, (vtimestamp - vstepsize) + vapproxtime, ... vapproxvals, [], vfunarguments{:}); end end vpltret = feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', [], vfunarguments{:}); if (vpltret), vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vu(:), vhmat}, [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizegiven) %# vdelta may be 0 or even negative - could be an iteration problem vdelta = max (vdelta, eps); vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); elseif (vstepsizegiven) if (vcntloop < vtimelength) vstepsize = vslot(1,vcntloop-1) - vslot(1,vcntloop-2); end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for postprocessing vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vtimestamp < vtimestop) if (vunhandledtermination == true) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:HideWarning', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult(vcntloop-1,:), vhmat}, 'done', vfunarguments{:}); end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 7*(vcntcycles-1); %# number of ode evaluations vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode54d'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end %# else nothing will be returned, varargout{1} undefined end %! # We are using a "pseudo-DDE" implementation for all tests that %! # are done for this function. We also define an Events and a %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn. %!function [vyd] = fexp (vt, vy, vz, varargin) %! vyd(1,1) = exp (- vt) - vz(1); %# The DDEs that are %! vyd(2,1) = vy(1) - vz(2); %# used for all examples %!function [vval, vtrm, vdir] = feve (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = zeros (2,1); %# don't stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vval, vtrm, vdir] = fevn (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = ones (2,1); %# stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vmas] = fmas (vt, vy, vz, varargin) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy, vz, varargin) %! vmas = sparse ([1, 0; 0, 1]); %# A dummy sparse matrix %!function [vref] = fref () %# The reference solution %! vref = [0.12194462133618, 0.01652432423938]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = ode54d (1, [0 5], [1; 0], 1, [1; 0]); %!error %# input argument number two %! B = ode54d (@fexp, 1, [1; 0], 1, [1; 0]); %!error %# input argument number three %! B = ode54d (@fexp, [0 5], 1, 1, [1; 0]); %!error %# input argument number four %! B = ode54d (@fexp, [0 5], [1; 0], [1; 1], [1; 0]); %!error %# input argument number five %! B = ode54d (@fexp, [0 5], [1; 0], 1, 1); %!test %# one output argument %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode54d'); %!test %# two output arguments %! [vt, vy] = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 1e-1); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 1e-1); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! faym = @(vt, vy, vz) [exp(-vt) - vz(1); vy(1) - vz(2)]; %! vsol = ode54d (faym, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# extra input arguments passed trhough %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-7, 'RelTol', 1e-7); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# RelTol and NormControl option %! vopt = odeset ('AbsTol', 1e-7, 'NormControl', 'on'); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], .5e-1); %!test %# NonNegative for second component %! vopt = odeset ('NonNegative', 1); %! vsol = ode54d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2.5, 0.001, 0.237], 1e-1); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode54d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode54d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie, [1; 1]); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vie, vxe, vye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 1e-1); %! %! %# test for Jacobian option is missing %! %# test for Jacobian (being a sparse matrix) is missing %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 1e-1); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode54d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vt(end), vy(end,:)], [5, fref], 0.5); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidOption'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/ode78.m0000644000176000010400000010671411742512661015305 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode78 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode78 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode78 (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff ordinary differential equations (non--stiff ODEs) or non--stiff differential algebraic equations (non--stiff DAEs) with the well known explicit Runge--Kutta method of order (7,8). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example, solve an anonymous implementation of the Van der Pol equation %# %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# %# vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ %# "NormControl", "on", "OutputFcn", @@odeplot); %# ode78 (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} %# ChangeLog: %# 20010519 the function file "ode78.m" was written by Marc Compere %# under the GPL for the use with this software. This function has been %# taken as a base for the following implementation. %# 20060810, Thomas Treichl %# This function was adapted to the new syntax that is used by the %# new OdePkg for Octave. An equivalent function in Matlab does not %# exist. function [varargout] = ode78 (vfun, vslot, vinit, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode78'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 3) print_usage; elseif ~(isa (vfun, 'function_handle') || isa (vfun, 'inline')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (nargin >= 4) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode78'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode78'); vfunarguments = {}; end else %# if (nargin == 3) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options are set in %# vodeoptions, check if an invalid or unused option is set vslot = vslot(:).'; %# Create a row vector vinit = vinit(:).'; %# Create a row vector if (length (vslot) > 2) %# Step size checking vstepsizefixed = true; else vstepsizefixed = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizefixed) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizefixed) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else vodeoptions.AbsTol = vodeoptions.AbsTol(:); %# Create column vector end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')) vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidArgument', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option OutputSave has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputSave)), vodeoptions.OutputSave = 1; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (vodeoptions.Refine > 0), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizefixed) vodeoptions.InitialStep = (vslot(1,2) - vslot(1,1)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidArgument', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizefixed) vodeoptions.MaxStep = abs (vslot(1,2) - vslot(1,1)) / 10; warning ('OdePkg:InvalidArgument', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidArgument', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidArgument', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidArgument', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidArgument', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidArgument', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode78 vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value %# 20110611, reported by Nils Strunk %# Make it possible to solve equations from negativ to zero, %# eg. vres = ode78 (@(t,y) y, [-2 0], 2); vdirection = sign (vtimestop - vtimestamp); %# Direction flag if (~vstepsizefixed) if (sign (vodeoptions.InitialStep) == vdirection) vstepsize = vodeoptions.InitialStep; else %# Fix wrong direction of InitialStep. vstepsize = - vodeoptions.InitialStep; end vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = vslot(1,2) - vslot(1,1); vminstepsize = sign (vstepsize) * eps; end vretvaltime = vtimestamp; %# first timestamp output vretvalresult = vinit; %# first solution output %# Initialize the OutputFcn if (vhaveoutputfunction) if (vhaveoutputselection) vretout = vretvalresult(vodeoptions.OutputSel); else vretout = vretvalresult; end feval (vodeoptions.OutputFcn, vslot.', ... vretout.', 'init', vfunarguments{:}); end %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vretvalresult.', 'init', vfunarguments{:}); end vpow = 1/8; %# MC2001: see p.91 in Ascher & Petzold va = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; %# The 7(8) coefficients 1/18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; %# Coefficients proved, tt 20060827 1/48, 1/16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1/32, 0, 3/32, 0, 0, 0, 0, 0, 0, 0, 0, 0; 5/16, 0, -75/64, 75/64, 0, 0, 0, 0, 0, 0, 0, 0; 3/80, 0, 0, 3/16, 3/20, 0, 0, 0, 0, 0, 0, 0; 29443841/614563906, 0, 0, 77736538/692538347, -28693883/1125000000, ... 23124283/1800000000, 0, 0, 0, 0, 0, 0; 16016141/946692911, 0, 0, 61564180/158732637, 22789713/633445777, ... 545815736/2771057229, -180193667/1043307555, 0, 0, 0, 0, 0; 39632708/573591083, 0, 0, -433636366/683701615, -421739975/2616292301, ... 100302831/723423059, 790204164/839813087, 800635310/3783071287, 0, 0, 0, 0; 246121993/1340847787, 0, 0, -37695042795/15268766246, -309121744/1061227803, ... -12992083/490766935, 6005943493/2108947869, 393006217/1396673457, ... 123872331/1001029789, 0, 0, 0; -1028468189/846180014, 0, 0, 8478235783/508512852, 1311729495/1432422823, ... -10304129995/1701304382, -48777925059/3047939560, 15336726248/1032824649, ... -45442868181/3398467696, 3065993473/597172653, 0, 0; 185892177/718116043, 0, 0, -3185094517/667107341, -477755414/1098053517, ... -703635378/230739211, 5731566787/1027545527, 5232866602/850066563, ... -4093664535/808688257, 3962137247/1805957418, 65686358/487910083, 0; 403863854/491063109, 0, 0, -5068492393/434740067, -411421997/543043805, ... 652783627/914296604, 11173962825/925320556, -13158990841/6184727034, ... 3936647629/1978049680, -160528059/685178525, 248638103/1413531060, 0]; vb7 = [13451932/455176623; 0; 0; 0; 0; -808719846/976000145; ... 1757004468/5645159321; 656045339/265891186; -3867574721/1518517206; ... 465885868/322736535; 53011238/667516719; 2/45; 0]; vb8 = [14005451/335480064; 0; 0; 0; 0; -59238493/1068277825; 181606767/758867731; ... 561292985/797845732; -1041891430/1371343529; 760417239/1151165299; ... 118820643/751138087; -528747749/2220607170; 1/4]; vc = sum (va, 2); %# The solver main loop - stop if the endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu' * zeros(1,13); vcntiter = 0; vunhandledtermination = true; vcntsave = 2; while ((vdirection * (vtimestamp) < vdirection * (vtimestop)) && ... (vdirection * (vstepsize) >= vdirection * (vminstepsize))) %# Hit the endpoint of the time slot exactely if (vdirection * (vtimestamp + vstepsize) > vdirection * vtimestop) %# vstepsize = vtimestop - vdirection * vtimestamp; %# 20110611, reported by Nils Strunk %# The endpoint of the time slot must be hit exactly, %# eg. vsol = ode78 (@(t,y) y, [0 -1], 1); vstepsize = vdirection * abs (abs (vtimestop) - abs (vtimestamp)); end %# Estimate the thirteen results when using this solver for j = 1:13 vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu.' + vstepsize * vk(:,1:j-1) * va(j,1:j-1).'; if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vfunarguments{:}); end end %# Compute the 7th and the 8th order estimation y7 = vu.' + vstepsize * (vk * vb7); y8 = vu.' + vstepsize * (vk * vb8); if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y7(vodeoptions.NonNegative) = abs (y7(vodeoptions.NonNegative)); y8(vodeoptions.NonNegative) = abs (y8(vodeoptions.NonNegative)); end if (vhaveoutputfunction && vhaverefine) vSaveVUForRefine = vu; end %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizefixed) if (~vnormcontrol) vdelta = abs (y8 - y7); vtau = max (vodeoptions.RelTol * abs (vu.'), vodeoptions.AbsTol); else vdelta = norm (y8 - y7, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu.', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizefixed == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y8.'; %# MC2001: the higher order estimation as "local extrapolation" %# Save the solution every vodeoptions.OutputSave steps if (mod (vcntloop-1,vodeoptions.OutputSave) == 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; vcntsave = vcntsave + 1; end vcntloop = vcntloop + 1; vcntiter = 0; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) for vcnt = 0:vodeoptions.Refine %# Approximation between told and t if (vhaverefine) %# Do interpolation vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine.' + vapproxtime * (vk * vb8); vapproxtime = (vtimestamp - vstepsize) + vapproxtime; else vapproxvals = vu.'; vapproxtime = vtimestamp; end if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end vpltret = feval (vodeoptions.OutputFcn, vapproxtime, ... vapproxvals, [], vfunarguments{:}); if vpltret %# Leave refinement loop break; end end if (vpltret) %# Leave main loop vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu(:), [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizefixed) %# 20080425, reported by Marco Caliari %# vdelta cannot be negative (because of the absolute value that %# has been introduced) but it could be 0, then replace the zeros %# with the maximum value of vdelta vdelta(find (vdelta == 0)) = max (vdelta); %# It could happen that max (vdelta) == 0 (ie. that the original %# vdelta was 0), in that case we double the previous vstepsize vdelta(find (vdelta == 0)) = max (vtau) .* (0.4 ^ (1 / vpow)); if (vdirection == 1) vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); else vstepsize = max (- vodeoptions.MaxStep, ... max (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); end else %# if (vstepsizefixed) if (vcntloop <= vtimelength) vstepsize = vslot(vcntloop) - vslot(vcntloop-1); else %# Get out of the main integration loop break; end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for cost statistics vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vdirection * vtimestamp < vdirection * vtimestop) if (vunhandledtermination == true) error ('OdePkg:InvalidArgument', ... ['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:InvalidArgument', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vu.', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu.', 'done', vfunarguments{:}); end %# Save the last step, if not already saved if (mod (vcntloop-2,vodeoptions.OutputSave) ~= 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 13*(vcntcycles-1); %# number of ode evaluations vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d\n', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d\n', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d\n', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode78'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end end end %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference sol %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidArgument'); %! B = ode78 (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = ode78 (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = ode78 (@flor, [0 25], 1); %!test %# one output argument %! vsol = ode78 (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode78'); %!test %# two output arguments %! [vt, vy] = ode78 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode78 (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = ode78 (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed through %! vsol = ode78 (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode78 (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %!test %# Solve vdp in fixed step sizes %! vsol = ode78 (@fpol, [0:0.1:2], [2 0]); %! assert (vsol.x(:), [0:0.1:2]'); %! assert (vsol.y(end,:), fref, 1e-3); %!test %# Solve in backward direction starting at t=0 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode78 (@fpol, [0 -2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve in backward direction starting at t=2 %! vref = [-1.205364552835178, 0.951542399860817]; %! vsol = ode78 (@fpol, [2 -2], fref); %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3); %!test %# Solve another anonymous function in backward direction %! vref = [-1, 0.367879437558975]; %! vsol = ode78 (@(t,y) y, [0 -1], 1); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# Solve another anonymous function below zero %! vref = [0, 14.77810590694212]; %! vsol = ode78 (@(t,y) y, [-2 0], 2); %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, 2, 0], 3e-1); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %!test %# Details of OutputSave can't be tested %! vopt = odeset ('OutputSave', 1, 'OutputSel', 1); %! vsla = ode78 (@fpol, [0 2], [2 0], vopt); %! vopt = odeset ('OutputSave', 2); %! vslb = ode78 (@fpol, [0 2], [2 0], vopt); %! assert (length (vsla.x) > length (vslb.x)) %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode78 (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode78 (@fpol, [0 0.2], [2 0], vopt); %! %# assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-3); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve, 'InitialStep', 1e-4); %! vsol = ode78 (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! vopt = odeset ('Events', @fevn, 'InitialStep', 1e-4); %! vsol = ode78 (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 2e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'InitialStep', 1e-4); %! [vt, vy, vxe, vye, vie] = ode78 (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 2e-1); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode78 (@fpol, [0 2], [2 0], vopt); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidArgument'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/ode78d.m0000644000176000010400000010747511742512661015456 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} ode78d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} ode78d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode78d (@var{@@fun}, @var{slot}, @var{init}, @var{lags}, @var{hist}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of non--stiff delay differential equations (non--stiff DDEs) with a modified version of the well known explicit Runge--Kutta method of order (7,8). %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of DDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{lags} is a double vector that describes the lags of time, @var{hist} is a double matrix and describes the history of the DDEs, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# In other words, this function will solve a problem of the form %# @example %# dy/dt = fun (t, y(t), y(t-lags(1), y(t-lags(2), @dots{}))) %# y(slot(1)) = init %# y(slot(1)-lags(1)) = hist(1), y(slot(1)-lags(2)) = hist(2), @dots{} %# @end example %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of DDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example: %# @itemize @minus %# @item %# the following code solves an anonymous implementation of a chaotic behavior %# %# @example %# fcao = @@(vt, vy, vz) [2 * vz / (1 + vz^9.65) - vy]; %# %# vopt = odeset ("NormControl", "on", "RelTol", 1e-3); %# vsol = ode78d (fcao, [0, 100], 0.5, 2, 0.5, vopt); %# %# vlag = interp1 (vsol.x, vsol.y, vsol.x - 2); %# plot (vsol.y, vlag); legend ("fcao (t,y,z)"); %# @end example %# %# @item %# to solve the following problem with two delayed state variables %# %# @example %# d y1(t)/dt = -y1(t) %# d y2(t)/dt = -y2(t) + y1(t-5) %# d y3(t)/dt = -y3(t) + y2(t-10)*y1(t-10) %# @end example %# %# one might do the following %# %# @example %# function f = fun (t, y, yd) %# f(1) = -y(1); %% y1' = -y1(t) %# f(2) = -y(2) + yd(1,1); %% y2' = -y2(t) + y1(t-lags(1)) %# f(3) = -y(3) + yd(2,2)*yd(1,2); %% y3' = -y3(t) + y2(t-lags(2))*y1(t-lags(2)) %# endfunction %# T = [0,20] %# res = ode78d (@@fun, T, [1;1;1], [5, 10], ones (3,2)); %# @end example %# %# @end itemize %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = ode78d (vfun, vslot, vinit, vlags, vhist, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('ode78d'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 5) print_usage; elseif (~isa (vfun, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (~isvector (vlags) || ~isnumeric (vlags)) error ('OdePkg:InvalidArgument', ... 'Fourth input argument must be a valid numerical value'); elseif ~(isnumeric (vhist) || isa (vhist, 'function_handle')) error ('OdePkg:InvalidArgument', ... 'Fifth input argument must either be numeric or a function handle'); elseif (nargin >= 6) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'ode78d'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'ode78d'); vfunarguments = {}; end else %# if (nargin == 5) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options have been set in %# vodeoptions. Check if an invalid or unused option has been set and %# print warnings. vslot = vslot(:)'; %# Create a row vector vinit = vinit(:)'; %# Create a row vector vlags = vlags(:)'; %# Create a row vector %# Check if the user has given fixed points of time if (length (vslot) > 2), vstepsizegiven = true; %# Step size checking else vstepsizegiven = false; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizegiven) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); %# This implementation has been added to odepkg_structure_check.m %# elseif (~isscalar (vodeoptions.RelTol) && ~vstepsizegiven) %# error ('OdePkg:InvalidOption', ... %# 'Option "RelTol" must be set to a scalar value for this solver'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizegiven) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizegiven) warning ('OdePkg:InvalidOption', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else %# create column vector vodeoptions.AbsTol = vodeoptions.AbsTol(:); end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')), vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option NonNegative has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.NonNegative)) if (isempty (vodeoptions.Mass)), vhavenonnegative = true; else vhavenonnegative = false; warning ('OdePkg:InvalidOption', ... 'Option "NonNegative" will be ignored if mass matrix is set'); end else vhavenonnegative = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option Refine has been finished. This option %# can be set by the user to another value than default value. if (isequal (vodeoptions.Refine, vodetemp.Refine)), vhaverefine = true; else vhaverefine = false; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizegiven) vodeoptions.InitialStep = abs (vslot(1,1) - vslot(1,2)) / 10; vodeoptions.InitialStep = vodeoptions.InitialStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizegiven) vodeoptions.MaxStep = abs (vslot(1,1) - vslot(1,length (vslot))) / 10; %# vodeoptions.MaxStep = vodeoptions.MaxStep / 10^vodeoptions.Refine; warning ('OdePkg:InvalidOption', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored %# by this solver because this solver uses an explicit Runge-Kutta %# method and therefore no Jacobian calculation is necessary if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian)) warning ('OdePkg:InvalidOption', ... 'Option "Jacobian" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidOption', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidOption', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol)) warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxNewtonIterations,... vodetemp.MaxNewtonIterations)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" will be ignored by this solver'); end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; %# vmass = diag (ones (length (vinit), 1), 0); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidOption', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidOption', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidOption', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidOption', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidOption', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver ode78d vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value if (~vstepsizegiven) vstepsize = vodeoptions.InitialStep; vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = abs (vslot(1,1) - vslot(1,2)); vminstepsize = eps; %# vslot(1,2) - vslot(1,1) - eps; end vretvaltime = vtimestamp; %# first timestamp output if (vhaveoutputselection) %# first solution output vretvalresult = vinit(vodeoptions.OutputSel); else vretvalresult = vinit; end %# Initialize the OutputFcn if (vhaveoutputfunction) feval (vodeoptions.OutputFcn, vslot', ... vretvalresult', 'init', vfunarguments{:}); end %# Initialize the History if (isnumeric (vhist)) vhmat = vhist; vhavehistnumeric = true; else %# it must be a function handle for vcnt = 1:length (vlags); vhmat(:,vcnt) = feval (vhist, (vslot(1)-vlags(vcnt)), vfunarguments{:}); end vhavehistnumeric = false; end %# Initialize DDE variables for history calculation vsaveddetime = [vtimestamp - vlags, vtimestamp]'; vsaveddeinput = [vhmat, vinit']'; vsavedderesult = [vhmat, vinit']'; %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult', vhmat}, 'init', vfunarguments{:}); end vpow = 1/8; %# MC2001: see p.91 in Ascher & Petzold va = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; %# The 7(8) coefficients 1/18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; %# Coefficients proved, tt 20060827 1/48, 1/16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 1/32, 0, 3/32, 0, 0, 0, 0, 0, 0, 0, 0, 0; 5/16, 0, -75/64, 75/64, 0, 0, 0, 0, 0, 0, 0, 0; 3/80, 0, 0, 3/16, 3/20, 0, 0, 0, 0, 0, 0, 0; 29443841/614563906, 0, 0, 77736538/692538347, -28693883/1125000000, ... 23124283/1800000000, 0, 0, 0, 0, 0, 0; 16016141/946692911, 0, 0, 61564180/158732637, 22789713/633445777, ... 545815736/2771057229, -180193667/1043307555, 0, 0, 0, 0, 0; 39632708/573591083, 0, 0, -433636366/683701615, -421739975/2616292301, ... 100302831/723423059, 790204164/839813087, 800635310/3783071287, 0, 0, 0, 0; 246121993/1340847787, 0, 0, -37695042795/15268766246, -309121744/1061227803, ... -12992083/490766935, 6005943493/2108947869, 393006217/1396673457, ... 123872331/1001029789, 0, 0, 0; -1028468189/846180014, 0, 0, 8478235783/508512852, 1311729495/1432422823, ... -10304129995/1701304382, -48777925059/3047939560, 15336726248/1032824649, ... -45442868181/3398467696, 3065993473/597172653, 0, 0; 185892177/718116043, 0, 0, -3185094517/667107341, -477755414/1098053517, ... -703635378/230739211, 5731566787/1027545527, 5232866602/850066563, ... -4093664535/808688257, 3962137247/1805957418, 65686358/487910083, 0; 403863854/491063109, 0, 0, -5068492393/434740067, -411421997/543043805, ... 652783627/914296604, 11173962825/925320556, -13158990841/6184727034, ... 3936647629/1978049680, -160528059/685178525, 248638103/1413531060, 0]; vb7 = [13451932/455176623; 0; 0; 0; 0; -808719846/976000145; ... 1757004468/5645159321; 656045339/265891186; -3867574721/1518517206; ... 465885868/322736535; 53011238/667516719; 2/45; 0]; vb8 = [14005451/335480064; 0; 0; 0; 0; -59238493/1068277825; 181606767/758867731; ... 561292985/797845732; -1041891430/1371343529; 760417239/1151165299; ... 118820643/751138087; -528747749/2220607170; 1/4]; vc = sum (va, 2); %# The solver main loop - stop if the endpoint has been reached vcntloop = 2; vcntcycles = 1; vu = vinit; vk = vu' * zeros(1,13); vcntiter = 0; vunhandledtermination = true; while ((vtimestamp < vtimestop && vstepsize >= vminstepsize)) %# Hit the endpoint of the time slot exactely if ((vtimestamp + vstepsize) > vtimestop) vstepsize = vtimestop - vtimestamp; end %# Estimate the thirteen results when using this solver for j = 1:13 vthetime = vtimestamp + vc(j,1) * vstepsize; vtheinput = vu' + vstepsize * vk(:,1:j-1) * va(j,1:j-1)'; %# Claculate the history values (or get them from an external %# function) that are needed for the next step of solving if (vhavehistnumeric) for vcnt = 1:length (vlags) %# Direct implementation of a 'quadrature cubic Hermite interpolation' %# found at the Faculty for Mathematics of the University of Stuttgart %# http://mo.mathematik.uni-stuttgart.de/inhalt/aussage/aussage1269 vnumb = find (vthetime - vlags(vcnt) >= vsaveddetime); velem = min (vnumb(end), length (vsaveddetime) - 1); vstep = vsaveddetime(velem+1) - vsaveddetime(velem); vdiff = (vthetime - vlags(vcnt) - vsaveddetime(velem)) / vstep; vsubs = 1 - vdiff; %# Calculation of the coefficients for the interpolation algorithm vua = (1 + 2 * vdiff) * vsubs^2; vub = (3 - 2 * vdiff) * vdiff^2; vva = vstep * vdiff * vsubs^2; vvb = -vstep * vsubs * vdiff^2; vhmat(:,vcnt) = vua * vsaveddeinput(velem,:)' + ... vub * vsaveddeinput(velem+1,:)' + ... vva * vsavedderesult(velem,:)' + ... vvb * vsavedderesult(velem+1,:)'; end else %# the history must be a function handle for vcnt = 1:length (vlags) vhmat(:,vcnt) = feval ... (vhist, vthetime - vlags(vcnt), vfunarguments{:}); end end if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, vtheinput, vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, vthetime, vfunarguments{:}); end vk(:,j) = vmass \ feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); else vk(:,j) = feval ... (vfun, vthetime, vtheinput, vhmat, vfunarguments{:}); end end %# Compute the 7th and the 8th order estimation y7 = vu' + vstepsize * (vk * vb7); y8 = vu' + vstepsize * (vk * vb8); if (vhavenonnegative) vu(vodeoptions.NonNegative) = abs (vu(vodeoptions.NonNegative)); y7(vodeoptions.NonNegative) = abs (y7(vodeoptions.NonNegative)); y8(vodeoptions.NonNegative) = abs (y8(vodeoptions.NonNegative)); end vSaveVUForRefine = vu; %# Calculate the absolute local truncation error and the acceptable error if (~vstepsizegiven) if (~vnormcontrol) vdelta = y8 - y7; vtau = max (vodeoptions.RelTol * vu', vodeoptions.AbsTol); else vdelta = norm (y8 - y7, Inf); vtau = max (vodeoptions.RelTol * max (norm (vu', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizegiven == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y8'; %# MC2001: the higher order estimation as "local extrapolation" vretvaltime(vcntloop,:) = vtimestamp; if (vhaveoutputselection) vretvalresult(vcntloop,:) = vu(vodeoptions.OutputSel); else vretvalresult(vcntloop,:) = vu; end vcntloop = vcntloop + 1; vcntiter = 0; %# Update DDE values for next history calculation vsaveddetime(end+1) = vtimestamp; vsaveddeinput(end+1,:) = vtheinput'; vsavedderesult(end+1,:) = vu; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) if (vhaverefine) %# Do interpolation for vcnt = 0:vodeoptions.Refine %# Approximation between told and t vapproxtime = (vcnt + 1) * vstepsize / (vodeoptions.Refine + 2); vapproxvals = vSaveVUForRefine' + vapproxtime * (vk * vb8); if (vhaveoutputselection) vapproxvals = vapproxvals(vodeoptions.OutputSel); end feval (vodeoptions.OutputFcn, (vtimestamp - vstepsize) + vapproxtime, ... vapproxvals, [], vfunarguments{:}); end end vpltret = feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', [], vfunarguments{:}); if (vpltret), vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vu(:), vhmat}, [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizegiven) %# vdelta may be 0 or even negative - could be an iteration problem vdelta = max (vdelta, eps); vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); elseif (vstepsizegiven) if (vcntloop < vtimelength) vstepsize = vslot(1,vcntloop-1) - vslot(1,vcntloop-2); end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for postprocessing vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vtimestamp < vtimestop) if (vunhandledtermination == true) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:HideWarning', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vretvalresult(vcntloop-1,:)', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... {vretvalresult(vcntloop-1,:), vhmat}, 'done', vfunarguments{:}); end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = 13*(vcntcycles-1); %# number of ode evaluations vndecomps = 0; %# number of LU decompositions vnpds = 0; %# number of partial derivatives vnlinsols = 0; %# no. of solutions of linear systems %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'ode78d'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end %# else nothing will be returned, varargout{1} undefined end %! # We are using a "pseudo-DDE" implementation for all tests that %! # are done for this function. We also define an Events and a %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn. %!function [vyd] = fexp (vt, vy, vz, varargin) %! vyd(1,1) = exp (- vt) - vz(1); %# The DDEs that are %! vyd(2,1) = vy(1) - vz(2); %# used for all examples %!function [vval, vtrm, vdir] = feve (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = zeros (2,1); %# don't stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vval, vtrm, vdir] = fevn (vt, vy, vz, varargin) %! vval = fexp (vt, vy, vz); %# We use the derivatives %! vtrm = ones (2,1); %# stop solving here %! vdir = ones (2,1); %# in positive direction %!function [vmas] = fmas (vt, vy, vz, varargin) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy, vz, varargin) %! vmas = sparse ([1, 0; 0, 1]); %# A dummy sparse matrix %!function [vref] = fref () %# The reference solution %! vref = [0.12194462133618, 0.01652432423938]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = ode78d (1, [0 5], [1; 0], 1, [1; 0]); %!error %# input argument number two %! B = ode78d (@fexp, 1, [1; 0], 1, [1; 0]); %!error %# input argument number three %! B = ode78d (@fexp, [0 5], 1, 1, [1; 0]); %!error %# input argument number four %! B = ode78d (@fexp, [0 5], [1; 0], [1; 1], [1; 0]); %!error %# input argument number five %! B = ode78d (@fexp, [0 5], [1; 0], 1, 1); %!test %# one output argument %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode78d'); %!test %# two output arguments %! [vt, vy] = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 0.2); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0]); %! assert ([vt(end), vy(end,:)], [5, fref], 0.2); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! faym = @(vt, vy, vz) [exp(-vt) - vz(1); vy(1) - vz(2)]; %! vsol = ode78d (faym, [0 5], [1; 0], 1, [1; 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# extra input arguments passed trhough %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-7, 'RelTol', 1e-7); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# RelTol and NormControl option %! vopt = odeset ('AbsTol', 1e-7, 'NormControl', 'on'); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# NonNegative for second component %! vopt = odeset ('NonNegative', 1); %! vsol = ode78d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2.5, 0.001, 0.237], 0.2); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode78d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode78d (@fexp, [0 2.5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie, [1; 1]); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 0.2); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vie, vxe, vye], ... %! [1.0000, 2.9219, -0.2127, -0.2671], 0.2); %! %! %# test for Jacobian option is missing %! %# test for Jacobian (being a sparse matrix) is missing %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for NewtonTol option is missing %! %# test for MaxNewtonIterations option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [5, fref], 0.2); %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! [vt, vy] = ode78d (@fexp, [0 5], [1; 0], 1, [1; 0], vopt); %! assert ([vt(end), vy(end,:)], [5, fref], 0.5); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %! warning ('on', 'OdePkg:InvalidOption'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odebwe.m0000644000176000010400000010526111742510713015614 0ustar marcoAdministrators%# Copyright (C) 2009-2012, Sebastian Schoeps %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} odebwe (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{sol}] =} odebwe (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odebwe (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}]) %# %# This function file can be used to solve a set of stiff ordinary differential equations (stiff ODEs) or stiff differential algebraic equations (stiff DAEs) with the Backward Euler method. %# %# If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}. %# %# If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}. %# %# If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector. %# %# For example, solve an anonymous implementation of the Van der Pol equation %# %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# vjac = @@(vt,vy) [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %# vopt = odeset ("RelTol", 1e-3, "AbsTol", 1e-3, \ %# "NormControl", "on", "OutputFcn", @@odeplot, \ %# "Jacobian",vjac); %# odebwe (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = odebwe (vfun, vslot, vinit, varargin) if (nargin == 0) %# Check number and types of all input arguments help ('odebwe'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin < 3) print_usage; elseif ~(isa (vfun, 'function_handle') || isa (vfun, 'inline')) error ('OdePkg:InvalidArgument', ... 'First input argument must be a valid function handle'); elseif (~isvector (vslot) || length (vslot) < 2) error ('OdePkg:InvalidArgument', ... 'Second input argument must be a valid vector'); elseif (~isvector (vinit) || ~isnumeric (vinit)) error ('OdePkg:InvalidArgument', ... 'Third input argument must be a valid numerical value'); elseif (nargin >= 4) if (~isstruct (varargin{1})) %# varargin{1:len} are parameters for vfun vodeoptions = odeset; vfunarguments = varargin; elseif (length (varargin) > 1) %# varargin{1} is an OdePkg options structure vopt vodeoptions = odepkg_structure_check (varargin{1}, 'odebwe'); vfunarguments = {varargin{2:length(varargin)}}; else %# if (isstruct (varargin{1})) vodeoptions = odepkg_structure_check (varargin{1}, 'odebwe'); vfunarguments = {}; end else %# if (nargin == 3) vodeoptions = odeset; vfunarguments = {}; end %# Start preprocessing, have a look which options are set in %# vodeoptions, check if an invalid or unused option is set vslot = vslot(:).'; %# Create a row vector vinit = vinit(:).'; %# Create a row vector if (length (vslot) > 2) %# Step size checking vstepsizefixed = true; else vstepsizefixed = false; end %# The adaptive method require a second estimate for %# the comparsion, while the fixed step size algorithm %# needs only one if ~vstepsizefixed vestimators = 2; else vestimators = 1; end %# Get the default options that can be set with 'odeset' temporarily vodetemp = odeset; %# Implementation of the option RelTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.RelTol) && ~vstepsizefixed) vodeoptions.RelTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" not set, new value %f is used', vodeoptions.RelTol); elseif (~isempty (vodeoptions.RelTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "RelTol" will be ignored if fixed time stamps are given'); end %# Implementation of the option AbsTol has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.AbsTol) && ~vstepsizefixed) vodeoptions.AbsTol = 1e-6; warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" not set, new value %f is used', vodeoptions.AbsTol); elseif (~isempty (vodeoptions.AbsTol) && vstepsizefixed) warning ('OdePkg:InvalidArgument', ... 'Option "AbsTol" will be ignored if fixed time stamps are given'); else vodeoptions.AbsTol = vodeoptions.AbsTol(:); %# Create column vector end %# Implementation of the option NormControl has been finished. This %# option can be set by the user to another value than default value. if (strcmp (vodeoptions.NormControl, 'on')) vnormcontrol = true; else vnormcontrol = false; end %# Implementation of the option OutputFcn has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputFcn) && nargout == 0) vodeoptions.OutputFcn = @odeplot; vhaveoutputfunction = true; elseif (isempty (vodeoptions.OutputFcn)), vhaveoutputfunction = false; else vhaveoutputfunction = true; end %# Implementation of the option OutputSel has been finished. This %# option can be set by the user to another value than default value. if (~isempty (vodeoptions.OutputSel)), vhaveoutputselection = true; else vhaveoutputselection = false; end %# Implementation of the option OutputSave has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.OutputSave)), vodeoptions.OutputSave = 1; end %# Implementation of the option Stats has been finished. This option %# can be set by the user to another value than default value. %# Implementation of the option InitialStep has been finished. This %# option can be set by the user to another value than default value. if (isempty (vodeoptions.InitialStep) && ~vstepsizefixed) vodeoptions.InitialStep = (vslot(1,2) - vslot(1,1)) / 10; warning ('OdePkg:InvalidArgument', ... 'Option "InitialStep" not set, new value %f is used', vodeoptions.InitialStep); end %# Implementation of the option MaxNewtonIterations has been finished. This option %# can be set by the user to another value than default value. if isempty (vodeoptions.MaxNewtonIterations) vodeoptions.MaxNewtonIterations = 10; warning ('OdePkg:InvalidArgument', ... 'Option "MaxNewtonIterations" not set, new value %f is used', vodeoptions.MaxNewtonIterations); end %# Implementation of the option NewtonTol has been finished. This option %# can be set by the user to another value than default value. if isempty (vodeoptions.NewtonTol) vodeoptions.NewtonTol = 1e-7; warning ('OdePkg:InvalidArgument', ... 'Option "NewtonTol" not set, new value %f is used', vodeoptions.NewtonTol); end %# Implementation of the option MaxStep has been finished. This option %# can be set by the user to another value than default value. if (isempty (vodeoptions.MaxStep) && ~vstepsizefixed) vodeoptions.MaxStep = (vslot(1,2) - vslot(1,1)) / 10; warning ('OdePkg:InvalidArgument', ... 'Option "MaxStep" not set, new value %f is used', vodeoptions.MaxStep); end %# Implementation of the option Events has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Events)), vhaveeventfunction = true; else vhaveeventfunction = false; end %# Implementation of the option Jacobian has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Jacobian) && isnumeric (vodeoptions.Jacobian)) vhavejachandle = false; vjac = vodeoptions.Jacobian; %# constant jac elseif (isa (vodeoptions.Jacobian, 'function_handle')) vhavejachandle = true; %# jac defined by a function handle else %# no Jacobian - we will use numerical differentiation vhavejachandle = false; end %# Implementation of the option Mass has been finished. This option %# can be set by the user to another value than default value. if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass)) vhavemasshandle = false; vmass = vodeoptions.Mass; %# constant mass elseif (isa (vodeoptions.Mass, 'function_handle')) vhavemasshandle = true; %# mass defined by a function handle else %# no mass matrix - creating a diag-matrix of ones for mass vhavemasshandle = false; vmass = sparse (eye (length (vinit)) ); end %# Implementation of the option MStateDependence has been finished. %# This option can be set by the user to another value than default %# value. if (strcmp (vodeoptions.MStateDependence, 'none')) vmassdependence = false; else vmassdependence = true; end %# Other options that are not used by this solver. Print a warning %# message to tell the user that the option(s) is/are ignored. if (~isequal (vodeoptions.NonNegative, vodetemp.NonNegative)) warning ('OdePkg:InvalidArgument', ... 'Option "NonNegative" will be ignored by this solver'); end if (~isequal (vodeoptions.Refine, vodetemp.Refine)) warning ('OdePkg:InvalidArgument', ... 'Option "Refine" will be ignored by this solver'); end if (~isequal (vodeoptions.JPattern, vodetemp.JPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "JPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized)) warning ('OdePkg:InvalidArgument', ... 'Option "Vectorized" will be ignored by this solver'); end if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern)) warning ('OdePkg:InvalidArgument', ... 'Option "MvPattern" will be ignored by this solver'); end if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular)) warning ('OdePkg:InvalidArgument', ... 'Option "MassSingular" will be ignored by this solver'); end if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope)) warning ('OdePkg:InvalidArgument', ... 'Option "InitialSlope" will be ignored by this solver'); end if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder)) warning ('OdePkg:InvalidArgument', ... 'Option "MaxOrder" will be ignored by this solver'); end if (~isequal (vodeoptions.BDF, vodetemp.BDF)) warning ('OdePkg:InvalidArgument', ... 'Option "BDF" will be ignored by this solver'); end %# Starting the initialisation of the core solver odebwe vtimestamp = vslot(1,1); %# timestamp = start time vtimelength = length (vslot); %# length needed if fixed steps vtimestop = vslot(1,vtimelength); %# stop time = last value vdirection = sign (vtimestop); %# Flag for direction to solve if (~vstepsizefixed) vstepsize = vodeoptions.InitialStep; vminstepsize = (vtimestop - vtimestamp) / (1/eps); else %# If step size is given then use the fixed time steps vstepsize = vslot(1,2) - vslot(1,1); vminstepsize = sign (vstepsize) * eps; end vretvaltime = vtimestamp; %# first timestamp output vretvalresult = vinit; %# first solution output %# Initialize the OutputFcn if (vhaveoutputfunction) if (vhaveoutputselection) vretout = vretvalresult(vodeoptions.OutputSel); else vretout = vretvalresult; end feval (vodeoptions.OutputFcn, vslot.', ... vretout.', 'init', vfunarguments{:}); end %# Initialize the EventFcn if (vhaveeventfunction) odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vretvalresult.', 'init', vfunarguments{:}); end %# Initialize parameters and counters vcntloop = 2; vcntcycles = 1; vu = vinit; vcntsave = 2; vunhandledtermination = true; vpow = 1/2; vnpds = 0; vcntiter = 0; vcntnewt = 0; vndecomps = 0; vnlinsols = 0; %# the following option enables the simplified Newton method %# which evaluates the Jacobian only once instead of the %# standard method that updates the Jacobian in each iteration vsimplified = false; % or true %# The solver main loop - stop if the endpoint has been reached while ((vdirection * (vtimestamp) < vdirection * (vtimestop)) && ... (vdirection * (vstepsize) >= vdirection * (vminstepsize))) %# Hit the endpoint of the time slot exactely if ((vtimestamp + vstepsize) > vdirection * vtimestop) vstepsize = vtimestop - vdirection * vtimestamp; end %# Run the time integration for each estimator %# from vtimestamp -> vtimestamp+vstepsize for j = 1:vestimators %# Initial value (result of the previous timestep) y0 = vu; %# Initial guess for Newton-Raphson y(j,:) = vu; %# We do not use a higher order approximation for the %# comparsion, but two steps by the Backward Euler %# method for i = 1:j % Initialize the time stepping parameters vthestep = vstepsize / j; vthetime = vtimestamp + i*vthestep; vnewtit = 1; vresnrm = inf (1, vodeoptions.MaxNewtonIterations); %# Start the Newton iteration while (vnewtit < vodeoptions.MaxNewtonIterations) && ... (vresnrm (vnewtit) > vodeoptions.NewtonTol) %# Compute the Jacobian of the non-linear equation, %# that is the matrix pencil of the mass matrix and %# the right-hand-side's Jacobian. Perform a (sparse) %# LU-Decomposition afterwards. if ( (vnewtit==1) || (~vsimplified) ) %# Get the mass matrix from the left-hand-side if (vhavemasshandle) %# Handle only the dynamic mass matrix, if (vmassdependence) %# constant mass matrices have already vmass = feval ... %# been set before (if any) (vodeoptions.Mass, vthetime, y(j,:)', vfunarguments{:}); else %# if (vmassdependence == false) vmass = feval ... %# then we only have the time argument (vodeoptions.Mass, y(j,:)', vfunarguments{:}); end end %# Get the Jacobian of the right-hand-side's function if (vhavejachandle) %# Handle only the dynamic jacobian vjac = feval(vodeoptions.Jacobian, vthetime,... y(j,:)', vfunarguments{:}); elseif isempty(vodeoptions.Jacobian) %# If no Jacobian is given vjac = feval(@jacobian, vfun, vthetime,y(j,:)',... vfunarguments); %# then we differentiate end vnpds = vnpds + 1; vfulljac = vmass/vthestep - vjac; %# one could do a matrix decomposition of vfulljac here, %# but the choice of decomposition depends on the problem %# and therefore we use the backslash-operator in row 374 end %# Compute the residual vres = vmass/vthestep*(y(j,:)-y0)' - feval(vfun,vthetime,y(j,:)',vfunarguments{:}); vresnrm(vnewtit+1) = norm(vres,inf); %# Solve the linear system y(j,:) = vfulljac\(-vres+vfulljac*y(j,:)'); %# the backslash operator decomposes the matrix %# and solves the system in a single step. vndecomps = vndecomps + 1; vnlinsols = vnlinsols + 1; %# Prepare next iteration vnewtit = vnewtit + 1; end %# while Newton %# Leave inner loop if Newton diverged if vresnrm(vnewtit)>vodeoptions.NewtonTol break; end %# Save intermediate solution as initial value %# for the next intermediate step y0 = y(j,:); %# Count all Newton iterations vcntnewt = vcntnewt + (vnewtit-1); end %# for steps %# Leave outer loop if Newton diverged if vresnrm(vnewtit)>vodeoptions.NewtonTol break; end end %# for estimators % if all Newton iterations converged if vresnrm(vnewtit)vodeoptions.NewtonTol vdelta = 2; vtau = 1; elseif (~vstepsizefixed) if (~vnormcontrol) vdelta = abs (y3 - y1)'; vtau = max (vodeoptions.RelTol * abs (vu.'), vodeoptions.AbsTol); else vdelta = norm ((y3 - y1)', Inf); vtau = max (vodeoptions.RelTol * max (norm (vu.', Inf), 1.0), ... vodeoptions.AbsTol); end else %# if (vstepsizefixed == true) vdelta = 1; vtau = 2; end %# If the error is acceptable then update the vretval variables if (all (vdelta <= vtau)) vtimestamp = vtimestamp + vstepsize; vu = y2; % or y3 if we want the extrapolation.... %# Save the solution every vodeoptions.OutputSave steps if (mod (vcntloop-1,vodeoptions.OutputSave) == 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; vcntsave = vcntsave + 1; end vcntloop = vcntloop + 1; vcntiter = 0; %# Call plot only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if plot function %# returns false if (vhaveoutputfunction) if (vhaveoutputselection) vpltout = vu(vodeoptions.OutputSel); else vpltout = vu; end vpltret = feval (vodeoptions.OutputFcn, vtimestamp, ... vpltout.', [], vfunarguments{:}); if vpltret %# Leave loop vunhandledtermination = false; break; end end %# Call event only if a valid result has been found, therefore this %# code fragment has moved here. Stop integration if veventbreak is %# true if (vhaveeventfunction) vevent = ... odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu(:), [], vfunarguments{:}); if (~isempty (vevent{1}) && vevent{1} == 1) vretvaltime(vcntloop-1,:) = vevent{3}(end,:); vretvalresult(vcntloop-1,:) = vevent{4}(end,:); vunhandledtermination = false; break; end end end %# If the error is acceptable ... %# Update the step size for the next integration step if (~vstepsizefixed) %# 20080425, reported by Marco Caliari %# vdelta cannot be negative (because of the absolute value that %# has been introduced) but it could be 0, then replace the zeros %# with the maximum value of vdelta vdelta(find (vdelta == 0)) = max (vdelta); %# It could happen that max (vdelta) == 0 (ie. that the original %# vdelta was 0), in that case we double the previous vstepsize vdelta(find (vdelta == 0)) = max (vtau) .* (0.4 ^ (1 / vpow)); if (vdirection == 1) vstepsize = min (vodeoptions.MaxStep, ... min (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); else vstepsize = max (vodeoptions.MaxStep, ... max (0.8 * vstepsize * (vtau ./ vdelta) .^ vpow)); end else %# if (vstepsizefixed) if (vresnrm(vnewtit)>vodeoptions.NewtonTol) vunhandledtermination = true; break; elseif (vcntloop <= vtimelength) vstepsize = vslot(vcntloop) - vslot(vcntloop-1); else %# Get out of the main integration loop break; end end %# Update counters that count the number of iteration cycles vcntcycles = vcntcycles + 1; %# Needed for cost statistics vcntiter = vcntiter + 1; %# Needed to find iteration problems %# Stop solving because the last 1000 steps no successful valid %# value has been found if (vcntiter >= 5000) error (['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f before endpoint at', ... ' tend = %f was reached. This happened because the iterative', ... ' integration loop does not find a valid solution at this time', ... ' stamp. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); end end %# The main loop %# Check if integration of the ode has been successful if (vdirection * vtimestamp < vdirection * vtimestop) if (vunhandledtermination == true) error ('OdePkg:InvalidArgument', ... ['Solving has not been successful. The iterative', ... ' integration loop exited at time t = %f', ... ' before endpoint at tend = %f was reached. This may', ... ' happen if the stepsize grows smaller than defined in', ... ' vminstepsize. Try to reduce the value of "InitialStep" and/or', ... ' "MaxStep" with the command "odeset".\n'], vtimestamp, vtimestop); else warning ('OdePkg:InvalidArgument', ... ['Solver has been stopped by a call of "break" in', ... ' the main iteration loop at time t = %f before endpoint at', ... ' tend = %f was reached. This may happen because the @odeplot', ... ' function returned "true" or the @event function returned "true".'], ... vtimestamp, vtimestop); end end %# Postprocessing, do whatever when terminating integration algorithm if (vhaveoutputfunction) %# Cleanup plotter feval (vodeoptions.OutputFcn, vtimestamp, ... vu.', 'done', vfunarguments{:}); end if (vhaveeventfunction) %# Cleanup event function handling odepkg_event_handle (vodeoptions.Events, vtimestamp, ... vu.', 'done', vfunarguments{:}); end %# Save the last step, if not already saved if (mod (vcntloop-2,vodeoptions.OutputSave) ~= 0) vretvaltime(vcntsave,:) = vtimestamp; vretvalresult(vcntsave,:) = vu; end %# Print additional information if option Stats is set if (strcmp (vodeoptions.Stats, 'on')) vhavestats = true; vnsteps = vcntloop-2; %# vcntloop from 2..end vnfailed = (vcntcycles-1)-(vcntloop-2)+1; %# vcntcycl from 1..end vnfevals = vcntnewt; %# number of rhs evaluations if isempty(vodeoptions.Jacobian) %# additional evaluations due vnfevals = vnfevals + vcntnewt*(1+length(vinit)); %# to differentiation end %# Print cost statistics if no output argument is given if (nargout == 0) vmsg = fprintf (1, 'Number of successful steps: %d\n', vnsteps); vmsg = fprintf (1, 'Number of failed attempts: %d\n', vnfailed); vmsg = fprintf (1, 'Number of function calls: %d\n', vnfevals); end else vhavestats = false; end if (nargout == 1) %# Sort output variables, depends on nargout varargout{1}.x = vretvaltime; %# Time stamps are saved in field x varargout{1}.y = vretvalresult; %# Results are saved in field y varargout{1}.solver = 'odebwe'; %# Solver name is saved in field solver if (vhaveeventfunction) varargout{1}.ie = vevent{2}; %# Index info which event occured varargout{1}.xe = vevent{3}; %# Time info when an event occured varargout{1}.ye = vevent{4}; %# Results when an event occured end if (vhavestats) varargout{1}.stats = struct; varargout{1}.stats.nsteps = vnsteps; varargout{1}.stats.nfailed = vnfailed; varargout{1}.stats.nfevals = vnfevals; varargout{1}.stats.npds = vnpds; varargout{1}.stats.ndecomps = vndecomps; varargout{1}.stats.nlinsols = vnlinsols; end elseif (nargout == 2) varargout{1} = vretvaltime; %# Time stamps are first output argument varargout{2} = vretvalresult; %# Results are second output argument elseif (nargout == 5) varargout{1} = vretvaltime; %# Same as (nargout == 2) varargout{2} = vretvalresult; %# Same as (nargout == 2) varargout{3} = []; %# LabMat doesn't accept lines like varargout{4} = []; %# varargout{3} = varargout{4} = []; varargout{5} = []; if (vhaveeventfunction) varargout{3} = vevent{3}; %# Time info when an event occured varargout{4} = vevent{4}; %# Results when an event occured varargout{5} = vevent{2}; %# Index info which event occured end end end function df = jacobian(vfun,vthetime,vtheinput,vfunarguments); %# Internal function for the numerical approximation of a jacobian vlen = length(vtheinput); vsigma = sqrt(eps); vfun0 = feval(vfun,vthetime,vtheinput,vfunarguments{:}); df = zeros(vlen,vlen); for j = 1:vlen vbuffer = vtheinput(j); if (vbuffer==0) vh = vsigma; elseif (abs(vbuffer)>1) vh = vsigma*vbuffer; else vh = sign(vbuffer)*vsigma; end vtheinput(j) = vbuffer + vh; df(:,j) = (feval(vfun,vthetime,vtheinput,... vfunarguments{:}) - vfun0) / vh; vtheinput(j) = vbuffer; end end %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference sol %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end %! elseif (isempty (vflag)) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidArgument'); %! B = odebwe (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = odebwe (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = odebwe (@flor, [0 25], 1); %!test %# one output argument %! vsol = odebwe (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'odebwe'); %!test %# two output arguments %! [vt, vy] = odebwe (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = odebwe (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = odebwe (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = odebwe (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = odebwe (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %!test %# Solve vdp in fixed step sizes %! vsol = odebwe (@fpol, [0:0.001:2], [2 0]); %! assert (vsol.x(:), [0:0.001:2]'); %! assert (vsol.y(end,:), fref, 1e-2); %!test %# Solve in backward direction starting at t=0 %! %# vref = [-1.2054034414, 0.9514292694]; %! vsol = odebwe (@fpol, [0 -2], [2 0]); %! %# assert ([vsol.x(end), vsol.y(end,:)], [-2, fref], 1e-3); %!test %# Solve in backward direction starting at t=2 %! %# vref = [-1.2154183302, 0.9433018000]; %! vsol = odebwe (@fpol, [2 -2], [0.3233166627 -1.8329746843]); %! %# assert ([vsol.x(end), vsol.y(end,:)], [-2, fref], 1e-3); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-2); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-6, 'RelTol', 1e-6); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-2); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-6, 'NormControl', 'on'); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for NonNegative option is missing %! %# test for OutputSel and Refine option is missing %! %!test %# Details of OutputSave can't be tested %! vopt = odeset ('OutputSave', 1, 'OutputSel', 1); %! vsla = odebwe (@fpol, [0 2], [2 0], vopt); %! vopt = odeset ('OutputSave', 2); %! vslb = odebwe (@fpol, [0 2], [2 0], vopt); %! assert (length (vsla.x) > length (vslb.x)) %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = odebwe (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = odebwe (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = odebwe (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie, [2; 1; 2; 1]); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = odebwe (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-3); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = odebwe (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-3); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = odebwe (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for MStateDependence option is missing %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %# test for BDF option is missing %! %! warning ('on', 'OdePkg:InvalidArgument'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odeexamples.m0000644000176000010400000000355011711232766016660 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; if not, write to the Free Software %# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} odeexamples (@var{}) %# Open the differential equations examples menu and allow the user to select a submenu of ODE, DAE, IDE or DDE examples. %# @end deftypefn function [] = odeexamples (varargin) vfam = 1; while (vfam > 0) clc; fprintf (1, ... ['OdePkg examples main menu:\n', ... '==========================\n', ... '\n', ... ' (1) Open the ODE examples menu\n', ... ' (2) Open the DAE examples menu\n', ... ' (3) Open the IDE examples menu\n', ... ' (4) Open the DDE examples menu\n', ... '\n']); vfam = input ('Please choose a number from above or press to return: '); switch (vfam) case 1 odepkg_examples_ode; case 2 odepkg_examples_dae; case 3 odepkg_examples_ide; case 4 odepkg_examples_dde; otherwise %# have nothing to do end end %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odeget.m0000644000176000010400000001340711711232766015623 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{value}] =} odeget (@var{odestruct}, @var{option}, [@var{default}]) %# @deftypefnx {Command} {[@var{values}] =} odeget (@var{odestruct}, @{@var{opt1}, @var{opt2}, @dots{}@}, [@{@var{def1}, @var{def2}, @dots{}@}]) %# %# If this function is called with two input arguments and the first input argument @var{odestruct} is of type structure array and the second input argument @var{option} is of type string then return the option value @var{value} that is specified by the option name @var{option} in the OdePkg option structure @var{odestruct}. Optionally if this function is called with a third input argument then return the default value @var{default} if @var{option} is not set in the structure @var{odestruct}. %# %# If this function is called with two input arguments and the first input argument @var{odestruct} is of type structure array and the second input argument @var{option} is of type cell array of strings then return the option values @var{values} that are specified by the option names @var{opt1}, @var{opt2}, @dots{} in the OdePkg option structure @var{odestruct}. Optionally if this function is called with a third input argument of type cell array then return the default value @var{def1} if @var{opt1} is not set in the structure @var{odestruct}, @var{def2} if @var{opt2} is not set in the structure @var{odestruct}, @dots{} %# %# Run examples with the command %# @example %# demo odeget %# @end example %# @end deftypefn %# %# @seealso{odepkg} %# Note: 20061022, Thomas Treichl %# We cannot create a function of the form odeget (@var{odestruct}, %# @var{name1}, @var{name2}) because we would get a mismatch with %# the function form 1 like described above. function [vret] = odeget (varargin) if (nargin == 0) %# Check number and types of input arguments vmsg = sprintf ('Number of input arguments must be greater than zero'); help ('odeget'); error (vmsg); elseif (isstruct (varargin{1}) == true) %# Check first input argument vint.odestruct = odepkg_structure_check (varargin{1}); vint.otemplate = odeset; %# Create default odepkg otpions structure else vmsg = sprintf ('First input argument must be a valid odepkg otpions structure'); error (vmsg); end %# Check number and types of other input arguments if (length (varargin) < 2 || length (varargin) > 3) vmsg = sprintf ('odeget (odestruct, "option", default) or\n odeget (odestruct, {"opt1", "opt2", ...}, {def1, def2, ...})'); usage (vmsg); elseif (ischar (varargin{2}) == true && isempty (varargin{2}) == false) vint.arguments = {varargin{2}}; vint.lengtharg = 1; elseif (iscellstr (varargin{2}) == true && isempty (varargin{2}) == false) vint.arguments = varargin{2}; vint.lengtharg = length (vint.arguments); end if (nargin == 3) %# Check if third input argument is valid if (iscell (varargin{3}) == true) vint.defaults = varargin{3}; vint.lengthdf = length (vint.defaults); else vint.defaults = {varargin{3}}; vint.lengthdf = 1; end if (vint.lengtharg ~= vint.lengthdf) vmsg = sprintf ('If third argument is given then sizes of argument 2 and argument 3 must be the equal'); error (vmsg); end end %# Run through number of input arguments given for vcntarg = 1:vint.lengtharg if ((... isempty(vint.odestruct.(vint.arguments{vcntarg})) )||( ... ischar(vint.odestruct.(vint.arguments{vcntarg})) && ... strcmp(vint.odestruct.(vint.arguments{vcntarg}),vint.otemplate.(vint.arguments{vcntarg}))... )||(... ~ischar(vint.odestruct.(vint.arguments{vcntarg})) && ... vint.odestruct.(vint.arguments{vcntarg}) == vint.otemplate.(vint.arguments{vcntarg}) ... )) if (nargin == 3), vint.returnval{vcntarg} = vint.defaults{vcntarg}; else, vint.returnval{vcntarg} = vint.odestruct.(vint.arguments{vcntarg}); end else, vint.returnval{vcntarg} = vint.odestruct.(vint.arguments{vcntarg}); end end %# Postprocessing, store results in the vret variable if (vint.lengtharg == 1), vret = vint.returnval{1}; else, vret = vint.returnval; end %!test assert (odeget (odeset (), 'RelTol'), []); %!test assert (odeget (odeset (), 'RelTol', 10), 10); %!test assert (odeget (odeset (), {'RelTol', 'AbsTol'}), {[] []}) %!test assert (odeget (odeset (), {'RelTol', 'AbsTol'}, {10 20}), {10 20}); %!test assert (odeget (odeset (), 'Stats'), 'off'); %!test assert (odeget (odeset (), 'Stats', 'on'), 'on'); %!demo %! # Return the manually changed value RelTol of the OdePkg options %! # strutcure A. If RelTol wouldn't have been changed then an %! # empty matrix value would have been returned. %! %! A = odeset ('RelTol', 1e-1, 'AbsTol', 1e-2); %! odeget (A, 'RelTol', []) %!demo %! # Return the manually changed value of RelTol and the value 1e-4 %! # for AbsTol of the OdePkg options structure A. %! %! A = odeset ('RelTol', 1e-1); %! odeget (A, {'RelTol', 'AbsTol'}, {1e-2, 1e-4}) %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odephas2.m0000644000176000010400000000664411711232766016066 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{ret}] =} odephas2 (@var{t}, @var{y}, @var{flag}) %# %# Open a new figure window and plot the first result from the variable @var{y} that is of type double column vector over the second result from the variable @var{y} while solving. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is %# @table @option %# @item @code{"init"} %# then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, %# @item @code{""} %# then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', %# @item @code{"done"} %# then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. %# @end table %# %# This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. %# %# For example, solve an anonymous implementation of the "Van der Pol" equation and display the results while solving in a 2D plane %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# %# vopt = odeset ('OutputFcn', @@odephas2, 'RelTol', 1e-6); %# vsol = ode45 (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = odephas2 (vt, vy, vflag) %# No input argument check is done for a higher processing speed persistent vfigure; persistent vyold; persistent vcounter; if (strcmp (vflag, 'init')) %# Nothing to return, vt is either the time slot [tstart tstop] %# or [t0, t1, ..., tn], vy is the inital value vector 'vinit' vfigure = figure; vyold = vy(:,1); vcounter = 1; elseif (isempty (vflag)) %# Return something in varargout{1}, either false for 'not stopping %# the integration' or true for 'stopping the integration' vcounter = vcounter + 1; figure (vfigure); vyold(:,vcounter) = vy(:,1); plot (vyold(1,:), vyold(2,:), '-o', 'markersize', 1); drawnow; varargout{1} = false; elseif (strcmp (vflag, 'done')) %# Cleanup has to be done, clear the persistent variables because %# we don't need them anymore clear ('vfigure', 'vyold', 'vcounter'); end %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odephas3.m0000644000176000010400000000721611711232766016063 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{ret}] =} odephas3 (@var{t}, @var{y}, @var{flag}) %# %# Open a new figure window and plot the first result from the variable @var{y} that is of type double column vector over the second and the third result from the variable @var{y} while solving. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is %# @table @option %# @item @code{"init"} %# then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, %# @item @code{""} %# then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', %# @item @code{"done"} %# then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. %# @end table %# %# This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. %# %# For example, solve the "Lorenz attractor" and display the results while solving in a 3D plane %# @example %# function vyd = florenz (vt, vx) %# vyd = [10 * (vx(2) - vx(1)); %# vx(1) * (28 - vx(3)); %# vx(1) * vx(2) - 8/3 * vx(3)]; %# endfunction %# %# vopt = odeset ('OutputFcn', @@odephas3); %# vsol = ode23 (@@florenz, [0:0.01:7.5], [3 15 1], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = odephas3 (vt, vy, vflag) %# vt and vy are always column vectors, vflag can be either 'init' %# or [] or 'done'. If 'init' then varargout{1} = [], if [] the %# varargout{1} either true or false, if 'done' then varargout{1} = []. persistent vfigure; persistent vyold; persistent vcounter; if (strcmp (vflag, 'init')) %# vt is either the time slot [tstart tstop] or [t0, t1, ..., tn] %# vy is the inital value vector vinit from the caller function vfigure = figure; vyold = vy(:,1); vcounter = 1; elseif (isempty (vflag)) %# Return something in varargout{1}, either false for 'not stopping %# the integration' or true for 'stopping the integration' vcounter = vcounter + 1; figure (vfigure); vyold(:,vcounter) = vy(:,1); plot3 (vyold(1,:), vyold(2,:), vyold (3,:), '-o', 'markersize', 1); drawnow; varargout{1} = false; elseif (strcmp (vflag, 'done')) %# Cleanup has to be done, clear the persistent variables because %# we don't need them anymore clear ('vfigure', 'vyold', 'vcounter'); end %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg.m0000644000176000010400000002156411742525067015633 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} odepkg () %# %# OdePkg is part of the GNU Octave Repository (the Octave--Forge project). The package includes commands for setting up various options, output functions etc. before solving a set of differential equations with the solver functions that are also included. At this time OdePkg is under development with the main target to make a package that is mostly compatible to proprietary solver products. %# %# If this function is called without any input argument then open the OdePkg tutorial in the Octave window. The tutorial can also be opened with the following command %# %# @example %# doc odepkg %# @end example %# @end deftypefn function [] = odepkg (vstr) %# Check number and types of all input arguments if (nargin == 0) doc ('odepkg'); elseif (nargin > 1) error ('Number of input arguments must be zero or one'); elseif (ischar (vstr)) feval (vstr); else error ('Input argument must be a valid string'); end function [] = odepkg_validate_mfiles () %# From command line in the 'inst' directory do something like this: %# octave --quiet --eval "odepkg ('odepkg_validate_mfiles')" vfun = {'ode23', 'ode45', 'ode54', 'ode78', ... 'ode23d', 'ode45d', 'ode54d', 'ode78d', ... 'odeget', 'odeset', 'odeplot', 'odephas2', 'odephas3', 'odeprint', ... 'odepkg_structure_check', 'odepkg_event_handle', ... 'odepkg_testsuite_calcscd', 'odepkg_testsuite_calcmescd'}; %# vfun = sort (vfun); for vcnt=1:length(vfun) printf ('Testing function %s ... ', vfun{vcnt}); test (vfun{vcnt}, 'quiet'); fflush (1); end function [] = odepkg_validate_ccfiles () %# From command line in the 'src' directory do something like this: %# octave --quiet --eval "odepkg ('odepkg_validate_ccfiles')" vfile = {'odepkg_octsolver_mebdfdae.cc', 'odepkg_octsolver_mebdfi.cc', ... 'odepkg_octsolver_ddaskr.cc', ... 'odepkg_octsolver_radau.cc', 'odepkg_octsolver_radau5.cc', ... 'odepkg_octsolver_rodas.cc', 'odepkg_octsolver_seulex.cc'}; vsolv = {'odebda', 'odebdi', 'odekdi', ... 'ode2r', 'ode5r', 'oders', 'odesx'}; %# vfile = {'odepkg_octsolver_ddaskr.cc'}; %# vsolv = {'odekdi'}; for vcnt=1:length(vfile) printf ('Testing function %s ... ', vsolv{vcnt}); autoload (vsolv{vcnt}, which ('dldsolver.oct')); test (vfile{vcnt}, 'quiet'); fflush (1); end function [] = odepkg_internal_mhelpextract () %# In the inst directory do %# octave --quiet --eval "odepkg ('odepkg_internal_mhelpextract')" vfun = {'odepkg', 'odeget', 'odeset', ... 'ode23', 'ode45', 'ode54', 'ode78', ... 'ode23d', 'ode45d', 'ode54d', 'ode78d', ... 'odebwe', ... 'odeplot', 'odephas2', 'odephas3', 'odeprint', ... 'odepkg_structure_check', 'odepkg_event_handle', ... 'odepkg_testsuite_calcscd', 'odepkg_testsuite_calcmescd', ... 'odepkg_testsuite_oregonator', 'odepkg_testsuite_pollution', ... 'odepkg_testsuite_hires', ... 'odepkg_testsuite_robertson', 'odepkg_testsuite_chemakzo', ... 'odepkg_testsuite_transistor', ... 'odepkg_testsuite_implrober', 'odepkg_testsuite_implakzo', ... 'odepkg_testsuite_imptrans', ... 'odeexamples', 'odepkg_examples_ode', 'odepkg_examples_dae', ... 'odepkg_examples_ide', 'odepkg_examples_dde'}; vfun = sort (vfun); [vout, vmsg] = fopen ('../doc/mfunref.texi', 'w'); if ~(isempty (vmsg)), error (vmsg); end for vcnt = 1:length (vfun) if (exist (vfun{vcnt}, 'file')) [vfid, vmsg] = fopen (which (vfun{vcnt}), 'r'); if ~(isempty (vmsg)), error (vmsg); end while (true) vlin = fgets (vfid); if ~(ischar (vlin)), break; end if (regexp (vlin, '^(%# -\*- texinfo -\*-)')) while (~isempty (regexp (vlin, '^(%#)')) && ... isempty (regexp (vlin, '^(%# @end deftypefn)'))) vlin = fgets (vfid); if (length (vlin) > 3), fprintf (vout, '%s', vlin(4:end)); else fprintf (vout, '%s', vlin(3:end)); end end fprintf (vout, '\n'); end end fclose (vfid); end end fclose (vout); function [] = odepkg_internal_octhelpextract () %# In the src directory do %# octave --quiet --eval "odepkg ('odepkg_internal_octhelpextract')" vfiles = {'../src/odepkg_octsolver_mebdfdae.cc', ... '../src/odepkg_octsolver_mebdfi.cc', ... '../src/odepkg_octsolver_ddaskr.cc', ... '../src/odepkg_octsolver_radau.cc', ... '../src/odepkg_octsolver_radau5.cc', ... '../src/odepkg_octsolver_rodas.cc', ... '../src/odepkg_octsolver_seulex.cc', ... }; %# vfiles = sort (vfiles); Don't sort these files [vout, vmsg] = fopen ('../doc/dldfunref.texi', 'w'); if ~(isempty (vmsg)), error (vmsg); end for vcnt = 1:length (vfiles) if (exist (vfiles{vcnt}, 'file')) [vfid, vmsg] = fopen (vfiles{vcnt}, 'r'); if ~(isempty (vmsg)), error (vmsg); end while (true) vlin = fgets (vfid); if ~(ischar (vlin)), break; end if (regexp (vlin, '^("-\*- texinfo -\*-\\n\\)')) %#" vlin = ' * '; %# Needed for the first call of while() while (isempty (regexp (vlin, '^(@end deftypefn)')) && ischar (vlin)) vlin = fgets (vfid); vlin = sprintf (regexprep (vlin, '\\n\\', '')); vlin = regexprep (vlin, '\\"', '"'); fprintf (vout, '%s', vlin); end fprintf (vout, '\n'); end end fclose (vfid); end end fclose (vout); function [] = odepkg_performance_mathires () vfun = {@ode113, @ode23, @ode45, ... @ode15s, @ode23s, @ode23t, @ode23tb}; for vcnt=1:length(vfun) vsol{vcnt, 1} = odepkg_testsuite_hires (vfun{vcnt}, 1e-7); end odepkg_testsuite_write (vsol); function [] = odepkg_performance_octavehires () vfun = {@ode23, @ode45, @ode54, @ode78, ... @ode2r, @ode5r, @oders, @odesx, @odebda}; for vcnt=1:length(vfun) vsol{vcnt, 1} = odepkg_testsuite_hires (vfun{vcnt}, 1e-7); end odepkg_testsuite_write (vsol); function [] = odepkg_performance_matchemakzo () vfun = {@ode23, @ode45, ... @ode15s, @ode23s, @ode23t, @ode23tb}; for vcnt=1:length(vfun) vsol{vcnt, 1} = odepkg_testsuite_chemakzo (vfun{vcnt}, 1e-7); end odepkg_testsuite_write (vsol); function [] = odepkg_performance_octavechemakzo () vfun = {@ode23, @ode45, @ode54, @ode78, ... @ode2r, @ode5r, @oders, @odesx, @odebda}; for vcnt=1:length(vfun) vsol{vcnt, 1} = odepkg_testsuite_chemakzo (vfun{vcnt}, 1e-7); end odepkg_testsuite_write (vsol); function [] = odepkg_testsuite_write (vsol) fprintf (1, ['-----------------------------------------------------------------------------------------\n']); fprintf (1, [' Solver RelTol AbsTol Init Mescd Scd Steps Accept FEval JEval LUdec Time\n']); fprintf (1, ['-----------------------------------------------------------------------------------------\n']); [vlin, vcol] = size (vsol); for vcntlin = 1:vlin if (isempty (vsol{vcntlin}{9})), vsol{vcntlin}{9} = 0; end %# if (vcntlin > 1) %# Delete solver name if it is the same as before %# if (strcmp (func2str (vsol{vcntlin}{1}), func2str (vsol{vcntlin-1}{1}))) %# vsol{vcntlin}{1} = ' '; %# end %# end fprintf (1, ['%7s %6.0g %6.0g %6.0g %5.2f %5.2f %5.0d %6.0d %5.0d %5.0d %5.0d %6.3f\n'], ... func2str (vsol{vcntlin}{1}), vsol{vcntlin}{2:12}); end fprintf (1, ['-----------------------------------------------------------------------------------------\n']); function [] = odepkg_internal_demos () vfun = {'odepkg', 'odeget', 'odeset', ... 'ode23', 'ode45', 'ode54', 'ode78', ... 'ode23d', 'ode45d', 'ode54d', 'ode78d', ... 'odeplot', 'odephas2', 'odephas3', 'odeprint', ... 'odepkg_structure_check', 'odepkg_event_handle'}; vfun = sort (vfun); for vcnt = 1:length (vfun), demo (vfun{vcnt}); end %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_event_handle.m0000644000176000010400000001742511711232766020345 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{sol}] =} odepkg_event_handle (@var{@@fun}, @var{time}, @var{y}, @var{flag}, [@var{par1}, @var{par2}, @dots{}]) %# %# Return the solution of the event function that is specified as the first input argument @var{@@fun} in form of a function handle. The second input argument @var{time} is of type double scalar and specifies the time of the event evaluation, the third input argument @var{y} either is of type double column vector (for ODEs and DAEs) and specifies the solutions or is of type cell array (for IDEs and DDEs) and specifies the derivatives or the history values, the third input argument @var{flag} is of type string and can be of the form %# @table @option %# @item @code{"init"} %# then initialize internal persistent variables of the function @command{odepkg_event_handle} and return an empty cell array of size 4, %# @item @code{"calc"} %# then do the evaluation of the event function and return the solution @var{sol} as type cell array of size 4, %# @item @code{"done"} %# then cleanup internal variables of the function @command{odepkg_event_handle} and return an empty cell array of size 4. %# @end table %# Optionally if further input arguments @var{par1}, @var{par2}, @dots{} of any type are given then pass these parameters through @command{odepkg_event_handle} to the event function. %# %# This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. %# @end deftypefn %# %# @seealso{odepkg} function [vretval] = odepkg_event_handle (vevefun, vt, vy, vflag, varargin) %# No error handling has been implemented in this function to achieve %# the highest performance available. %# vretval{1} is true or false; either to terminate or to continue %# vretval{2} is the index information for which event occured %# vretval{3} is the time information column vector %# vretval{4} is the line by line result information matrix %# These persistent variables are needed to store the results and the %# time value from the processing in the time stamp before, veveold %# are the results from the event function, vtold the time stamp, %# vretcell the return values cell array, vyold the result of the ode %# and vevecnt the counter for how often this event handling %# has been called persistent veveold; persistent vtold; persistent vretcell; persistent vyold; persistent vevecnt; %# Call the event function if an event function has been defined to %# initialize the internal variables of the event function an to get %# a value for veveold if (strcmp (vflag, 'init')) if (~iscell (vy)) vinpargs = {vevefun, vt, vy}; else vinpargs = {vevefun, vt, vy{1}, vy{2}}; vy = vy{1}; %# Delete cell element 2 end if (nargin > 4) vinpargs = {vinpargs{:}, varargin{:}}; end [veveold, vterm, vdir] = feval (vinpargs{:}); %# We assume that all return values must be column vectors veveold = veveold(:)'; vterm = vterm(:)'; vdir = vdir(:)'; vtold = vt; vyold = vy; vevecnt = 1; vretcell = cell (1,4); %# Process the event, find the zero crossings either for a rising %# or for a falling edge elseif (isempty (vflag)) if (~iscell (vy)) vinpargs = {vevefun, vt, vy}; else vinpargs = {vevefun, vt, vy{1}, vy{2}}; vy = vy{1}; %# Delete cell element 2 end if (nargin > 4) vinpargs = {vinpargs{:}, varargin{:}}; end [veve, vterm, vdir] = feval (vinpargs{:}); %# We assume that all return values must be column vectors veve = veve(:)'; vterm = vterm(:)'; vdir = vdir(:)'; %# Check if one or more signs of the event has changed vsignum = (sign (veveold) ~= sign (veve)); if (any (vsignum)) %# One or more values have changed vindex = find (vsignum); %# Get the index of the changed values if (any (vdir(vindex) == 0)) %# Rising or falling (both are possible) %# Don't change anything, keep the index elseif (any (vdir(vindex) == sign (veve(vindex)))) %# Detected rising or falling, need a new index vindex = find (vdir == sign (veve)); else %# Found a zero crossing but must not be notified vindex = []; end %# Create new output values if a valid index has been found if (~isempty (vindex)) %# Change the persistent result cell array vretcell{1} = any (vterm(vindex)); %# Stop integration or not vretcell{2}(vevecnt,1) = vindex(1,1); %# Take first event found %# Calculate the time stamp when the event function returned 0 and %# calculate new values for the integration results, we do both by %# a linear interpolation vtnew = vt - veve(1,vindex) * (vt - vtold) / (veve(1,vindex) - veveold(1,vindex)); vynew = (vy - (vt - vtnew) * (vy - vyold) / (vt - vtold))'; vretcell{3}(vevecnt,1) = vtnew; vretcell{4}(vevecnt,:) = vynew; vevecnt = vevecnt + 1; end %# if (~isempty (vindex)) end %# Check for one or more signs ... veveold = veve; vtold = vt; vretval = vretcell; vyold = vy; elseif (strcmp (vflag, 'done')) %# Clear this event handling function clear ('veveold', 'vtold', 'vretcell', 'vyold', 'vevecnt'); vretcell = cell (1,4); end %!function [veve, vterm, vdir] = feveode (vt, vy, varargin) %! veve = vy(1); %# Which event component should be treaded %! vterm = 1; %# Terminate if an event is found %! vdir = -1; %# In which direction, -1 for falling %!function [veve, vterm, vdir] = feveide (vt, vy, vyd, varargin) %! veve = vy(1); %# Which event component should be treaded %! vterm = 1; %# Terminate if an event is found %! vdir = -1; %# In which direction, -1 for falling %! %!test %# First call to initialize the odepkg_event_handle function %! odepkg_event_handle (@feveode, 0.0, [0 1 2 3], 'init', 123, 456); %!test %# Two calls to find the event that may occur with ODE/DAE syntax %! A = odepkg_event_handle (@feveode, 2.0, [ 0 0 3 2], '', 123, 456); %! B = odepkg_event_handle (@feveode, 3.0, [-1 0 3 2], '', 123, 456); %! assert (A, {[], [], [], []}); %! assert (B{4}, [0 0 3 2]); %!test %# Last call to cleanup the odepkg_event_handle function %! odepkg_event_handle (@feveode, 4.0, [0 1 2 3], 'done', 123, 456); %!test %# First call to initialize the odepkg_event_handle function %! odepkg_event_handle (@feveide, 0.0, {[0 1 2 3], [0 1 2 3]}, 'init', 123, 456); %!test %# Two calls to find the event that may occur with IDE/DDE syntax %! A = odepkg_event_handle (@feveide, 2.0, {[0 0 3 2], [0 0 3 2]}, '', 123, 456); %! B = odepkg_event_handle (@feveide, 3.0, {[-1 0 3 2], [0 0 3 2]}, '', 123, 456); %! assert (A, {[], [], [], []}); %! assert (B{4}, [0 0 3 2]); %!test %# Last call to cleanup the odepkg_event_handle function %! odepkg_event_handle (@feveide, 4.0, {[0 1 2 3], [0 1 2 3]}, 'done', 123, 456); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_examples_dae.m0000644000176000010400000000644311711232766020336 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} odepkg_examples_dae (@var{}) %# Open the DAE examples menu and allow the user to select a demo that will be evaluated. %# @end deftypefn function [] = odepkg_examples_dae () vode = 1; while (vode > 0) clc; fprintf (1, ... ['DAE examples menu:\n', ... '==================\n', ... '\n', ... ' (1) Solve the "Robertson problem" with solver "ode2r"\n', ... ' (2) Solve another "Robertson implementation" with solver "ode5r"\n', ... '\n', ... ' Note: There are further DAE examples available with the OdePkg\n', ... ' testsuite functions.\n', ... '\n', ... ' If you have another interesting DAE example that you would like\n', ... ' to share then please modify this file, create a patch and send\n', ... ' your patch with your added example to the OdePkg developer team.\n', ... '\n' ]); vode = input ('Please choose a number from above or press to return: '); clc; if (vode > 0 && vode < 3) %# We can't use the function 'demo' directly here because it does %# not allow to run other functions within a demo. vexa = example (mfilename (), vode); disp (vexa); eval (vexa); input ('Press to continue: '); end %# if (vode > 0) end %# while (vode > 0) %!demo %! # Solve the "Robertson problem" with a Mass function that is given by %! # a function handle. %! %! function [vyd] = frobertson (vt, vy, varargin) %! vyd(1,1) = -0.04 * vy(1) + 1e4 * vy(2) * vy(3); %! vyd(2,1) = 0.04 * vy(1) - 1e4 * vy(2) * vy(3) - 3e7 * vy(2)^2; %! vyd(3,1) = vy(1) + vy(2) + vy(3) - 1; %! endfunction %! %! function [vmass] = fmass (vt, vy, varargin) %! vmass = [1, 0, 0; 0, 1, 0; 0, 0, 0]; %! endfunction %! %! vopt = odeset ('Mass', @fmass, 'NormControl', 'on'); %! vsol = ode2r (@frobertson, [0, 1e5], [1, 0, 0], vopt); %! plot (vsol.x, vsol.y); %!demo %! # Solve the "Robertson problem" with a Mass function that is given by %! # a constant mass matrix. %! %! function [vyd] = frobertson (vt, vy, varargin) %! vyd(1,1) = -0.04 * vy(1) + 1e4 * vy(2) * vy(3); %! vyd(2,1) = 0.04 * vy(1) - 1e4 * vy(2) * vy(3) - 3e7 * vy(2)^2; %! vyd(3,1) = vy(1) + vy(2) + vy(3) - 1; %! endfunction %! %! vopt = odeset ('Mass', [1, 0, 0; 0, 1, 0; 0, 0, 0], ... %! 'NormControl', 'on'); %! vsol = ode5r (@frobertson, [0, 1e5], [1, 0, 0], vopt); %! plot (vsol.x, vsol.y); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_examples_dde.m0000644000176000010400000001230411711232766020332 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} odepkg_examples_dde (@var{}) %# Open the DDE examples menu and allow the user to select a demo that will be evaluated. %# @end deftypefn function [] = odepkg_examples_dde () vode = 1; while (vode > 0) clc; fprintf (1, ... ['DDE examples menu:\n', ... '==================\n', ... '\n', ... ' (1) Solve a simple "exp(...)" example with solver "ode23d"\n', ... ' (2) Solve an example from Wille and Baker with solver "ode45d"\n', ... ' (3) Solve an example from Hu and Wang with solver "ode54d"\n', ... ' (4) Solve the "infectious disease model" with solver "ode78d"\n', ... '\n', ... ' Note: There are further DDE examples available with the OdePkg\n', ... ' testsuite functions.\n', ... '\n', ... ' If you have another interesting DDE example that you would like\n', ... ' to share then please modify this file, create a patch and send\n', ... ' your patch with your added example to the OdePkg developer team.\n', ... '\n' ]); vode = input ('Please choose a number from above or press to return: '); clc; if (vode > 0 && vode < 5) %# We can't use the function 'demo' directly here because it does %# not allow to run other functions within a demo. vexa = example (mfilename (), vode); disp (vexa); eval (vexa); input ('Press to continue: '); end %# if (vode > 0) end %# while (vode > 0) %!demo %! # Solves a simple example where the delay differential equation is %! # of the form yd = e^(-lambda*t) - y(t-tau). %! %! function [vyd] = fexp (vt, vy, vz, varargin) %! vlambda = varargin{1}; %! vyd = exp (- vlambda * vt) - vz(1); %! endfunction %! %! vtslot = [0, 15]; vlambda = 1; vinit = 10; %! vopt = odeset ('NormControl', 'on', 'RelTol', 1e-4, 'AbsTol', 1e-4); %! vsol = ode23d (@fexp, vtslot, vinit, vlambda, vinit, vopt, vlambda); %! plot (vsol.x, vsol.y); %!demo %! # Solves the example 3 from the publication 'DELSOL - a numerical %! # code for the solution of systems of delay-differential equations' %! # from the authors David Wille and Christopher Baker. %! %! function [vyd] = fdelsol (vt, vy, vz, varargin) %! %# vy is a column vector of size (3,1) %! %# vz is the history of size (3,2) %! vyd = [vz(1,1); vz(1,1) + vz(2,2); vy(2,1)]; %! endfunction %! %! vopt = odeset ('NormControl', 'on', 'MaxStep', 0.1, 'InitialStep', 0.01); %! vsol = ode45d (@fdelsol, [0, 5], [1, 1, 1], [1, 0.2], ones(3,2), vopt); %! plot (vsol.x, vsol.y); %!demo %! # Solves the examples 2.3.1 and 2.3.2 from the book 'Dynamics of %! # Controlled Mechanical Systems with Delayed Feedback' from the %! # authors Haiyan Hu and Zaihua Wang. %! %! function [vyd] = fhuwang1 (vt, vy, vz, varargin) %! %# vy is of size (1,1), vz is of size (1,1) %! vyd = (vz(1,1) - varargin{1})^(1/3); %! endfunction %! %! function [vyd] = fhuwang2 (vt, vy, vz, varargin) %! %# vy is of size (1,1), vz is of size (1,1) %! vyd = (vy - vz)^(1/3); %! endfunction %! %! vtslot = [0, 10]; vK = 1; vinit = 1; vhist = 0; %! vopt = odeset ('NormControl', 'on', 'RelTol', 1e-6, 'InitialStep', 0.1); %! %! vsol = ode54d (@fhuwang1, vtslot, vK, vinit, vhist, vopt, vK); %! plot (vsol.x, vsol.y, 'ko-', 'markersize', 1); hold; %! %! vsol = ode54d (@fhuwang2, vtslot, vK, vinit, vhist, vopt, vK); %! plot (vsol.x, vsol.y, 'bx-', 'markersize', 1); %!demo %! # Solves the infectious disease model from the book 'Solving Ordinary %! # Differential Equations 1' from the authors Ernst Hairer and Gerhard %! # Wanner. %! %! function [vyd] = finfect (vx, vy, vz, varargin) %! %# vy is of size (3,1), vz is of size (3,2) %! vyd = [ - vy(1) * vz(2,1) + vz(2,2); %! vy(1) * vz(2,1) - vy(2); %! vy(2) - vz(2,2) ]; %! endfunction %! %! function [vval, vtrm, vdir] = fevent (vx, vy, vz, varargin) %! %# vy is of size (3,1), vz is of size (3,2) %! vfec = finfect (vx, vy, vz); %! vval = vfec(2:3); %# Have a look at component two + three %! vtrm = zeros(1,2); %# Don't stop if an event is found %! vdir = -ones(1,2); %# Check only for falling direction %! endfunction %! %! vopt = odeset ('InitialStep', 1e-3, 'Events', @fevent); %! vsol = ode78d (@finfect, [0, 40], [5, 0.1, 1], [1, 10], ... %! [5, 5; 0.1, 0.1; 1, 1], vopt); %! plot (vsol.x, vsol.y, 'k-', vsol.xe, vsol.ye, 'ro'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_examples_ide.m0000644000176000010400000001042111711232766020335 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} odepkg_examples_ide (@var{}) %# Open the IDE examples menu and allow the user to select a demo that will be evaluated. %# @end deftypefn function [] = odepkg_examples_ide () vode = 1; while (vode > 0) clc; fprintf (1, ... ['IDE examples menu:\n', ... '==================\n', ... '\n', ... ' (1) Solve the "Robertson problem" with solver "odebdi"\n', ... ' (2) Solve another "Robertson implementation" with solver "odekdi"\n', ... ' (3) Solve a stiff "Van der Pol" implementation with solver "odebdi"\n', ... ' (4) Solve a stiff "Van der Pol" implementation with solver "odekdi"\n', ... '\n', ... ' Note: There are further IDE examples available with the OdePkg\n', ... ' testsuite functions.\n', ... '\n', ... ' If you have another interesting IDE example that you would like\n', ... ' to share then please modify this file, create a patch and send\n', ... ' your patch to the OdePkg developer team.\n', ... '\n' ]); vode = input ('Please choose a number from above or press to return: '); clc; if (vode > 0 && vode < 5) %# We can't use the function 'demo' directly here because it does %# not allow to run other functions within a demo. vexa = example (mfilename (), vode); disp (vexa); eval (vexa); input ('Press to continue: '); end %# if (vode > 0) end %# while (vode > 0) %!demo %! # Solve the "Robertson problem" that is given as a function handle %! # to an implicite differential equation implementation. %! %! function [vres] = firobertson (vt, vy, vyd, varargin) %! vres(1,1) = -0.04*vy(1) + 1e4*vy(2)*vy(3) - vyd(1); %! vres(2,1) = 0.04*vy(1) - 1e4*vy(2)*vy(3) - 3e7*vy(2)^2-vyd(2); %! vres(3,1) = vy(1) + vy(2) + vy(3) - 1; %! endfunction %! %! vopt = odeset ("NormControl", "on"); %! vsol = odebdi (@firobertson, [0, 1e5], [1, 0, 0], [-4e-2, 4e-2, 0], vopt); %! plot (vsol.x, vsol.y); %!demo %! # Solve the "Robertson problem" that is given as a function handle %! # to an implicite differential equation implementation. %! %! function [vres] = firobertson (vt, vy, vyd, varargin) %! vres(1,1) = -0.04*vy(1) + 1e4*vy(2)*vy(3) - vyd(1); %! vres(2,1) = 0.04*vy(1) - 1e4*vy(2)*vy(3) - 3e7*vy(2)^2-vyd(2); %! vres(3,1) = vy(1) + vy(2) + vy(3) - 1; %! endfunction %! %! vopt = odeset ("NormControl", "on"); %! vsol = odekdi (@firobertson, [0, 1e5], [1, 0, 0], [-4e-2, 4e-2, 0], vopt); %! plot (vsol.x, vsol.y); %!demo %! # Solve the "Van der Pol" problem that is given as a function %! # handle to an implicite differential equation implementation. %! %! function [vres] = fvanderpol (vt, vy, vyd, varargin) %! mu = varargin{1}; %! vres = [vy(2) - vyd(1); %! mu * (1 - vy(1)^2) * vy(2) - vy(1) - vyd(2)]; %! endfunction %! %! vopt = odeset ("NormControl", "on", "RelTol", 1e-8, "MaxStep", 1e-2); %! vsol = odebdi (@fvanderpol, [0, 20], [2; 0], [0; -2], vopt, 10); %! plot (vsol.x, vsol.y); %!demo %! # Solve the "Van der Pol" problem that is given as a function %! # handle to an implicite differential equation implementation. %! %! function [vres] = fvanderpol (vt, vy, vyd, varargin) %! mu = varargin{1}; %! vres = [vy(2) - vyd(1); %! mu * (1 - vy(1)^2) * vy(2) - vy(1) - vyd(2)]; %! endfunction %! %! vsol = odekdi (@fvanderpol, [0, 1000], [2; 0], [0; -2], 500); %! plot (vsol.x, vsol.y); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_examples_ode.m0000644000176000010400000001610211742250600020334 0ustar marcoAdministrators%# Copyright (C) 2008-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{}] =} odepkg_examples_ode (@var{}) %# Open the ODE examples menu and allow the user to select a demo that will be evaluated. %# @end deftypefn function [] = odepkg_examples_ode () vode = 1; while (vode > 0) clc; fprintf (1, ... ['ODE examples menu:\n', ... '==================\n', ... '\n', ... ' (1) Solve a non-stiff "Van der Pol" example with solver "ode78"\n', ... ' (2) Solve a "Van der Pol" example backward with solver "ode23"\n', ... ' (3) Solve a "Pendulous" example with solver "ode45"\n', ... ' (4) Solve the "Lorenz attractor" with solver "ode54"\n', ... ' (5) Solve the "Roessler equation" with solver "ode78"\n', ... '\n', ... ' Note: There are further ODE examples available with the OdePkg\n', ... ' testsuite functions.\n', ... '\n', ... ' If you have another interesting ODE example that you would like\n', ... ' to share then please modify this file, create a patch and send\n', ... ' your patch with your added example to the OdePkg developer team.\n', ... '\n' ]); vode = input ('Please choose a number from above or press to return: '); clc; if (vode > 0 && vode < 6) %# We can't use the function 'demo' directly here because it does %# not allow to run other functions within a demo. vexa = example (mfilename (), vode); disp (vexa); eval (vexa); input ('Press to continue: '); end %# if (vode > 0) end %# while (vode > 0) %!demo %! # In this example the non-stiff "Van der Pol" equation (mu = 1) is %! # solved and the results are displayed in a figure while solving. %! # Read about the Van der Pol oscillator at %! # http://en.wikipedia.org/wiki/Van_der_Pol_oscillator. %! %! function [vyd] = fvanderpol (vt, vy, varargin) %! mu = varargin{1}; %! vyd = [vy(2); mu * (1 - vy(1)^2) * vy(2) - vy(1)]; %! endfunction %! %! vopt = odeset ('RelTol', 1e-8); %! ode78 (@fvanderpol, [0 20], [2 0], vopt, 1); %!demo %! # In this example the non-stiff "Van der Pol" equation (mu = 1) is %! # solved in forward and backward direction and the results are %! # displayed in a figure after solving. Read about the Van der Pol %! # oscillator at http://en.wikipedia.org/wiki/Van_der_Pol_oscillator. %! %! function [ydot] = fpol (vt, vy, varargin) %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! endfunction %! %! vopt = odeset ('NormControl', 'on'); %! vsol = ode23 (@fpol, [0, 20], [2, 0], vopt); %! subplot (2, 3, 1); plot (vsol.x, vsol.y); %! vsol = ode23 (@fpol, [0:0.1:20], [2, 0], vopt); %! subplot (2, 3, 2); plot (vsol.x, vsol.y); %! vsol = ode23 (@fpol, [-20, 20], [-1.1222e-3, -0.2305e-3], vopt); %! subplot (2, 3, 3); plot (vsol.x, vsol.y); %! %! vopt = odeset ('NormControl', 'on'); %! vsol = ode23 (@fpol, [0:-0.1:-20], [2, 0], vopt); %! subplot (2, 3, 4); plot (vsol.x, vsol.y); %! vsol = ode23 (@fpol, [0, -20], [2, 0], vopt); %! subplot (2, 3, 5); plot (vsol.x, vsol.y); %! vsol = ode23 (@fpol, [20:-0.1:-20], [-2.0080, 0.0462], vopt); %! subplot (2, 3, 6); plot (vsol.x, vsol.y); %!demo %! # In this example a simple "pendulum with damping" is solved and the %! # results are displayed in a figure while solving. Read about the %! # pendulum with damping at %! # http://en.wikipedia.org/wiki/Pendulum %! %! function [vyd] = fpendulum (vt, vy) %! m = 1; %# The pendulum mass in kg %! g = 9.81; %# The gravity in m/s^2 %! l = 1; %# The pendulum length in m %! b = 0.7; %# The damping factor in kgm^2/s %! vyd = [vy(2,1); ... %! 1 / (1/3 * m * l^2) * (-b * vy(2,1) - m * g * l/2 * sin (vy(1,1)))]; %! endfunction %! %! vopt = odeset ('RelTol', 1e-3, 'OutputFcn', @odeplot); %! ode45 (@fpendulum, [0 5], [30*pi/180, 0], vopt); %!demo %! # In this example the "Lorenz attractor" implementation is solved %! # and the results are plot in a figure after solving. Read about %! # the Lorenz attractor at %! # http://en.wikipedia.org/wiki/Lorenz_equation %! # %! # The upper left subfigure shows the three results of the integration %! # over time. The upper right subfigure shows the force f in a two %! # dimensional (x,y) plane as well as the lower left subfigure shows %! # the force in the (y,z) plane. The three dimensional force is plot %! # in the lower right subfigure. %! %! function [vyd] = florenz (vt, vy) %! vyd = [10 * (vy(2) - vy(1)); %! vy(1) * (28 - vy(3)); %! vy(1) * vy(2) - 8/3 * vy(3)]; %! endfunction %! %! A = odeset ('InitialStep', 1e-3, 'MaxStep', 1e-1); %! [t, y] = ode54 (@florenz, [0 25], [3 15 1], A); %! %! subplot (2, 2, 1); grid ('on'); %! plot (t, y(:,1), '-b', t, y(:,2), '-g', t, y(:,3), '-r'); %! legend ('f_x(t)', 'f_y(t)', 'f_z(t)'); %! subplot (2, 2, 2); grid ('on'); %! plot (y(:,1), y(:,2), '-b'); %! legend ('f_{xyz}(x, y)'); %! subplot (2, 2, 3); grid ('on'); %! plot (y(:,2), y(:,3), '-b'); %! legend ('f_{xyz}(y, z)'); %! subplot (2, 2, 4); grid ('on'); %! plot3 (y(:,1), y(:,2), y(:,3), '-b'); %! legend ('f_{xyz}(x, y, z)'); %!demo %! # In this example the "Roessler attractor" implementation is solved %! # and the results are plot in a figure after solving. Read about %! # the Roessler attractor at %! # http://en.wikipedia.org/wiki/R%C3%B6ssler_attractor %! # %! # The upper left subfigure shows the three results of the integration %! # over time. The upper right subfigure shows the force f in a two %! # dimensional (x,y) plane as well as the lower left subfigure shows %! # the force in the (y,z) plane. The three dimensional force is plot %! # in the lower right subfigure. %! %! function [vyd] = froessler (vt, vx) %! vyd = [- ( vx(2) + vx(3) ); %! vx(1) + 0.2 * vx(2); %! 0.2 + vx(1) * vx(3) - 5.7 * vx(3)]; %! endfunction %! %! A = odeset ('MaxStep', 1e-1); %! [t, y] = ode78 (@froessler, [0 70], [0.1 0.3 0.1], A); %! %! subplot (2, 2, 1); grid ('on'); %! plot (t, y(:,1), '-b;f_x(t);', t, y(:,2), '-g;f_y(t);', \ %! t, y(:,3), '-r;f_z(t);'); %! subplot (2, 2, 2); grid ('on'); %! plot (y(:,1), y(:,2), '-b;f_{xyz}(x, y);'); %! subplot (2, 2, 3); grid ('on'); %! plot (y(:,2), y(:,3), '-b;f_{xyz}(y, z);'); %! subplot (2, 2, 4); grid ('on'); %! plot3 (y(:,1), y(:,2), y(:,3), '-b;f_{xyz}(x, y, z);'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_structure_check.m0000644000176000010400000003760611742512661021110 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{newstruct}] =} odepkg_structure_check (@var{oldstruct}, [@var{"solver"}]) %# %# If this function is called with one input argument of type structure array then check the field names and the field values of the OdePkg structure @var{oldstruct} and return the structure as @var{newstruct} if no error is found. Optionally if this function is called with a second input argument @var{"solver"} of type string taht specifies the name of a valid OdePkg solver then a higher level error detection is performed. The function does not modify any of the field names or field values but terminates with an error if an invalid option or value is found. %# %# This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. %# %# Run examples with the command %# @example %# demo odepkg_structure_check %# @end example %# @end deftypefn %# %# @seealso{odepkg} function [vret] = odepkg_structure_check (varargin) %# Check the number of input arguments if (nargin == 0) help ('odepkg_structure_check'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (nargin > 2) print_usage; elseif (nargin == 1 && isstruct (varargin{1})) vret = varargin{1}; vsol = ''; vfld = fieldnames (vret); vlen = length (vfld); elseif (nargin == 2 && isstruct (varargin{1}) && ischar (varargin{2})) vret = varargin{1}; vsol = varargin{2}; vfld = fieldnames (vret); vlen = length (vfld); end for vcntarg = 1:vlen %# Run through the number of given structure field names switch (vfld{vcntarg}) case 'RelTol' if (isnumeric (vret.(vfld{vcntarg})) && ... isreal (vret.(vfld{vcntarg})) && ... all (vret.(vfld{vcntarg}) > 0)) %# 'all' is a MatLab need else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end switch (vsol) case {'ode23', 'ode45', 'ode54', 'ode78', ... 'ode23d', 'ode45d', 'ode54d', 'ode78d',} if (~isscalar (vret.(vfld{vcntarg})) && ... ~isempty (vret.(vfld{vcntarg}))) error ('OdePkg:InvalidParameter', ... 'Value of option "RelTol" must be a scalar'); end otherwise end case 'AbsTol' if (isnumeric (vret.(vfld{vcntarg})) && ... isreal (vret.(vfld{vcntarg})) && ... all (vret.(vfld{vcntarg}) > 0)) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'NormControl' if (strcmp (vret.(vfld{vcntarg}), 'on') || ... strcmp (vret.(vfld{vcntarg}), 'off')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'NonNegative' if (isempty (vret.(vfld{vcntarg})) || ... (isnumeric (vret.(vfld{vcntarg})) && isvector (vret.(vfld{vcntarg})))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'OutputFcn' if (isempty (vret.(vfld{vcntarg})) || ... isa (vret.(vfld{vcntarg}), 'function_handle')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'OutputSel' if (isempty (vret.(vfld{vcntarg})) || ... (isnumeric (vret.(vfld{vcntarg})) && isvector (vret.(vfld{vcntarg}))) || ... isscalar (vret.(vfld{vcntarg}))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'OutputSave' if (isempty (vret.(vfld{vcntarg})) || ... (isscalar (vret.(vfld{vcntarg})) && ... mod (vret.(vfld{vcntarg}), 1) == 0 && ... vret.(vfld{vcntarg}) > 0) || ... vret.(vfld{vcntarg}) == Inf) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'Refine' if (isscalar (vret.(vfld{vcntarg})) && ... mod (vret.(vfld{vcntarg}), 1) == 0 && ... vret.(vfld{vcntarg}) >= 0 && ... vret.(vfld{vcntarg}) <= 5) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'Stats' if (strcmp (vret.(vfld{vcntarg}), 'on') || ... strcmp (vret.(vfld{vcntarg}), 'off')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'InitialStep' if (isempty (vret.(vfld{vcntarg})) || ... (isscalar (vret.(vfld{vcntarg})) && ... isreal (vret.(vfld{vcntarg})))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'MaxStep' if (isempty (vret.(vfld{vcntarg})) || ... (isscalar (vret.(vfld{vcntarg})) && ... vret.(vfld{vcntarg}) > 0) ) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'Events' if (isempty (vret.(vfld{vcntarg})) || ... isa (vret.(vfld{vcntarg}), 'function_handle')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'Jacobian' if (isempty (vret.(vfld{vcntarg})) || ... isnumeric (vret.(vfld{vcntarg})) || ... isa (vret.(vfld{vcntarg}), 'function_handle') || ... iscell (vret.(vfld{vcntarg}))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'JPattern' if (isempty (vret.(vfld{vcntarg})) || ... isvector (vret.(vfld{vcntarg})) || ... isnumeric (vret.(vfld{vcntarg}))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'Vectorized' if (strcmp (vret.(vfld{vcntarg}), 'on') || ... strcmp (vret.(vfld{vcntarg}), 'off')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'Mass' if (isempty (vret.(vfld{vcntarg})) || ... isnumeric (vret.(vfld{vcntarg})) || ... isa (vret.(vfld{vcntarg}), 'function_handle')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'MStateDependence' if (strcmp (vret.(vfld{vcntarg}), 'none') || ... strcmp (vret.(vfld{vcntarg}), 'weak') || ... strcmp (vret.(vfld{vcntarg}), 'strong')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'MvPattern' if (isempty (vret.(vfld{vcntarg})) || ... isvector (vret.(vfld{vcntarg})) || ... isnumeric (vret.(vfld{vcntarg}))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'MassSingular' if (strcmp (vret.(vfld{vcntarg}), 'yes') || ... strcmp (vret.(vfld{vcntarg}), 'no') || ... strcmp (vret.(vfld{vcntarg}), 'maybe')) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'InitialSlope' if (isempty (vret.(vfld{vcntarg})) || ... isvector (vret.(vfld{vcntarg}))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'MaxOrder' if (isempty (vret.(vfld{vcntarg})) || ... (mod (vret.(vfld{vcntarg}), 1) == 0 && ... vret.(vfld{vcntarg}) > 0 && ... vret.(vfld{vcntarg}) < 8)) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'BDF' if (isempty (vret.(vfld{vcntarg})) || ... (strcmp (vret.(vfld{vcntarg}), 'on') || ... strcmp (vret.(vfld{vcntarg}), 'off'))) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'NewtonTol' if (isnumeric (vret.(vfld{vcntarg})) && ... isreal (vret.(vfld{vcntarg})) && ... all (vret.(vfld{vcntarg}) > 0)) %# 'all' is a MatLab need else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end case 'MaxNewtonIterations' if (isempty (vret.(vfld{vcntarg})) || ... (mod (vret.(vfld{vcntarg}), 1) == 0 && ... vret.(vfld{vcntarg}) > 0)) else error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s" or no valid parameter value', ... vfld{vcntarg}); end otherwise error ('OdePkg:InvalidParameter', ... 'Unknown parameter name "%s"', ... vfld{vcntarg}); end %# switch end %# for %# The following line can be uncommented for a even higher level error %# detection %# if (vlen ~= 21) %# vmsg = sprintf ('Number of fields in structure must match 21'); %# error (vmsg); %# end %!test A = odeset ('RelTol', 1e-4); %!test A = odeset ('RelTol', [1e-4, 1e-3]); %!test A = odeset ('RelTol', []); %!error A = odeset ('RelTol', '1e-4'); %!test A = odeset ('AbsTol', 1e-4); %!test A = odeset ('AbsTol', [1e-4, 1e-3]); %!test A = odeset ('AbsTol', []); %!error A = odeset ('AbsTol', '1e-4'); %!test A = odeset ('NormControl', 'on'); %!test A = odeset ('NormControl', 'off'); %!error A = odeset ('NormControl', []); %!error A = odeset ('NormControl', '12'); %!test A = odeset ('NonNegative', 1); %!test A = odeset ('NonNegative', [1, 2, 3]); %!test A = odeset ('NonNegative', []); %!error A = odeset ('NonNegative', '12'); %!test A = odeset ('OutputFcn', @odeprint); %!test A = odeset ('OutputFcn', @odeplot); %!test A = odeset ('OutputFcn', []); %!error A = odeset ('OutputFcn', 'odeprint'); %!test A = odeset ('OutputSel', 1); %!test A = odeset ('OutputSel', [1, 2, 3]); %!test A = odeset ('OutputSel', []); %!error A = odeset ('OutputSel', '12'); %!test A = odeset ('Refine', 3); %!error A = odeset ('Refine', [1, 2, 3]); %!error A = odeset ('Refine', []); %!error A = odeset ('Refine', 6); %!test A = odeset ('Stats', 'on'); %!test A = odeset ('Stats', 'off'); %!error A = odeset ('Stats', []); %!error A = odeset ('Stats', '12'); %!test A = odeset ('InitialStep', 3); %!error A = odeset ('InitialStep', [1, 2, 3]); %!test A = odeset ('InitialStep', []); %!test A = odeset ('InitialStep', 6); %!test A = odeset ('MaxStep', 3); %!error A = odeset ('MaxStep', [1, 2, 3]); %!test A = odeset ('MaxStep', []); %!test A = odeset ('MaxStep', 6); %!test A = odeset ('Events', @demo); %!error A = odeset ('Events', 'off'); %!test A = odeset ('Events', []); %!error A = odeset ('Events', '12'); %!test A = odeset ('Jacobian', @demo); %!test A = odeset ('Jacobian', [1, 2; 3, 4]); %!test A = odeset ('Jacobian', []); %!error A = odeset ('Jacobian', '12'); %!test A = odeset ('JPattern', []); %!test A = odeset ('JPattern', [1, 2, 4]); %!test A = odeset ('JPattern', [1, 2; 3, 4]); %!test A = odeset ('JPattern', 1); %!test A = odeset ('Vectorized', 'on'); %!test A = odeset ('Vectorized', 'off'); %!error A = odeset ('Vectorized', []); %!error A = odeset ('Vectorized', '12'); %!test A = odeset ('Mass', @demo); %!test A = odeset ('Mass', [1, 2; 3, 4]); %!test A = odeset ('Mass', []); %!error A = odeset ('Mass', '12'); %!test A = odeset ('MStateDependence', 'none'); %!test A = odeset ('MStateDependence', 'weak'); %!test A = odeset ('MStateDependence', 'strong'); %!error A = odeset ('MStateDependence', [1, 2; 3, 4]); %!error A = odeset ('MStateDependence', []); %!error A = odeset ('MStateDependence', '12'); %!test A = odeset ('MvPattern', []); %!test A = odeset ('MvPattern', [1, 2, 3 ]); %!test A = odeset ('MvPattern', [1, 2; 3, 4]); %!test A = odeset ('MvPattern', 1); %!test A = odeset ('MassSingular', 'yes'); %!test A = odeset ('MassSingular', 'no'); %!test A = odeset ('MassSingular', 'maybe'); %!error A = odeset ('MassSingular', [1, 2; 3, 4]); %!error A = odeset ('MassSingular', []); %!error A = odeset ('MassSingular', '12'); %!test A = odeset ('InitialSlope', [1, 2, 3]); %!test A = odeset ('InitialSlope', 1); %!test A = odeset ('InitialSlope', []); %!test A = odeset ('InitialSlope', '12'); %!test A = odeset ('MaxOrder', 3); %!error A = odeset ('MaxOrder', 3.5); %!test A = odeset ('MaxOrder', [1, 2; 3, 4]); %!test A = odeset ('MaxOrder', []); %!test A = odeset ('BDF', 'on'); %!test A = odeset ('BDF', 'off'); %!test A = odeset ('BDF', []); %!error A = odeset ('BDF', [1, 2; 3, 4]); %!test A = odeset ('NewtonTol', []); %!test A = odeset ('NewtonTol', 1e-3); %!test A = odeset ('NewtonTol', [1e-3, 1e-3, 1e-3]); %!error A = odeset ('NewtonTol', 'string'); %!test A = odeset ('MaxNewtonIterations', []); %!test A = odeset ('MaxNewtonIterations', 2); %!error A = odeset ('MaxNewtonIterations', 'string'); %!demo %! # Return the checked OdePkg options structure that is created by %! # the command odeset. %! %! odepkg_structure_check (odeset); %! %!demo %! # Create the OdePkg options structure A with odeset and check it %! # with odepkg_structure_check. This actually is unnecessary %! # because odeset automtically calls odepkg_structure_check before %! # returning. %! %! A = odeset (); odepkg_structure_check (A); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_calcmescd.m0000644000176000010400000000554211714561373021737 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{mescd}] =} odepkg_testsuite_calcmescd (@var{solution}, @var{reference}, @var{abstol}, @var{reltol}) %# %# If this function is called with four input arguments of type double scalar or column vector then return a normalized value for the minimum number of correct digits @var{mescd} that is calculated from the solution at the end of an integration interval @var{solution} and a set of reference values @var{reference}. The input arguments @var{abstol} and @var{reltol} are used to calculate a reference solution that depends on the relative and absolute error tolerances. %# %# Run examples with the command %# @example %# demo odepkg_testsuite_calcmescd %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vmescd = odepkg_testsuite_calcmescd (vsol, vref, vatol, vrtol) vsol = vsol(:); vref = vref(:); vatol = vatol(:); vrtol = vrtol(:); vtmp = (vref - vsol) ./ (vatol ./ vrtol + vref); vmescd = -log10 (norm (vtmp, inf)); %!demo %! # Display the value for the mimum number of correct digits in the vector %! # sol = [1, 2, 2.9] compared to the reference vector ref = [1, 2, 3]. %! %! odepkg_testsuite_calcmescd ([1, 2, 2.9], [1, 2, 3], 1e-3, 1e-6) %! %!demo %! # Display the value for the mimum number of correct digits in the vector %! # sol = [1 + 1e10, 2 + 1e10, 3 + 1e10] compared to the reference vector %! # ref = [1, 2, 3]. %! %! odepkg_testsuite_calcmescd ([1 + 1e10, 2 + 1e10, 3 + 1e10], [1, 2, 3], ... %! [1e-3, 1e-4, 1e-5], [1e-6, 1e-6, 1e-6]) %!assert (odepkg_testsuite_calcmescd ([1, 2, 3], [1, 2, 3], NaN, NaN), Inf); %!assert (odepkg_testsuite_calcmescd ([1, 2, 3], [1, 2, 3], 1, 1), Inf); %!assert (odepkg_testsuite_calcmescd ([1, 2, 3], [1, 2.1, 3], 1, 1), 1.5, 0.1); %!assert (odepkg_testsuite_calcmescd ([1, 2, 3], [1+1e-6, 2, 3], 1, 1), 6.5, 0.2); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_calcscd.m0000644000176000010400000000526511714561373021417 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{scd}] =} odepkg_testsuite_calcscd (@var{solution}, @var{reference}, @var{abstol}, @var{reltol}) %# %# If this function is called with four input arguments of type double scalar or column vector then return a normalized value for the minimum number of correct digits @var{scd} that is calculated from the solution at the end of an integration interval @var{solution} and a set of reference values @var{reference}. The input arguments @var{abstol} and @var{reltol} are unused but present because of compatibility to the function @command{odepkg_testsuite_calcmescd}. %# %# Run examples with the command %# @example %# demo odepkg_testsuite_calcscd %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vscd = odepkg_testsuite_calcscd (vsol, vref, vatol, vrtol) vsol = vsol(:); vref = vref(:); vrel = (vref - vsol) / vref; vscd = -log10 (norm (vrel, inf)); %!demo %! # Displays the value for the mimum number of correct digits in %! # the vector sol = [1, 2, 2.9] compared to the reference vector %! # ref = [1, 2, 3]. %! %! odepkg_testsuite_calcscd ([1, 2, 2.9], [1, 2, 3], NaN, NaN) %! %!demo %! # Displays the value for the mimum number of correct digits in %! # the vector sol = [1, 2, 2.9] compared to the reference vector %! # ref = [1, 2, 3]. %! %! odepkg_testsuite_calcscd ([1 + 1e10, 2 + 1e10, 3 + 1e10], ... %! [1, 2, 3], NaN, NaN) %!assert (odepkg_testsuite_calcscd ([1, 2, 3], [1, 2, 3], NaN, NaN), Inf); %!assert (odepkg_testsuite_calcscd ([1, 2, 3], [1, 2.1, 3], 1, 1), 1.5, 0.2); %!assert (odepkg_testsuite_calcscd ([1, 2, 3], [1+1e-6, 2, 3], 1, 1), 6.5, 0.2); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_chemakzo.m0000644000176000010400000001604611714561373021623 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_chemakzo (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the chemical AKZO Nobel testsuite of differential algebraic equations after solving (DAE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_chemakzo %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_chemakzo (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_chemakzo'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2}; %# The value for the absolute tolerance vret{4} = vret{2}; %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite AKZO, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 180.0; %# The point of time when solving is stoped vinit = odepkg_testsuite_chemakzoinit; %# The initial values vmass = odepkg_testsuite_chemakzomass; %# The mass matrix vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_chemakzojac, 'Mass', vmass, ... 'MaxStep', vstop-vstart); %# , 'OutputFcn', @odeplot); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_chemakzofun, ... [vstart, vstop], vinit, vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_chemakzoref; %# Get the reference solution vector if (max (size (vsol.y(end,:))) == max (size (vref))), vlst = vsol.y(end,:); elseif (max (size (vsol.y(:,end))) == max (size (vref))), vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Returns the results for the for the chemical AKZO problem function f = odepkg_testsuite_chemakzofun (t, y, varargin) k1 = 18.7; k2 = 0.58; k3 = 0.09; k4 = 0.42; kbig = 34.4; kla = 3.3; ks = 115.83; po2 = 0.9; hen = 737; %# if (y(2) <= 0) %# error ('odepkg_testsuite_chemakzojac: Second input argument is negative'); %# end r1 = k1 * y(1)^4 * sqrt (y(2)); r2 = k2 * y(3) * y(4); r3 = k2 / kbig * y(1) * y(5); r4 = k3 * y(1) * y(4)^2; r5 = k4 * y(6)^2 * sqrt (y(2)); fin = kla * (po2 / hen - y(2)); f(1,1) = -2 * r1 + r2 - r3 - r4; f(2,1) = -0.5 * r1 - r4 - 0.5 * r5 + fin; f(3,1) = r1 - r2 + r3; f(4,1) = - r2 + r3 - 2 * r4; f(5,1) = r2 - r3 + r5; f(6,1) = ks * y(1) * y(4) - y(6); %# Returns the INITIAL values for the chemical AKZO problem function vinit = odepkg_testsuite_chemakzoinit () vinit = [0.444, 0.00123, 0, 0.007, 0, 115.83 * 0.444 * 0.007]; %# Returns the JACOBIAN matrix for the chemical AKZO problem function dfdy = odepkg_testsuite_chemakzojac (t, y, varargin) k1 = 18.7; k2 = 0.58; k3 = 0.09; k4 = 0.42; kbig = 34.4; kla = 3.3; ks = 115.83; po2 = 0.9; hen = 737; %# if (y(2) <= 0) %# error ('odepkg_testsuite_chemakzojac: Second input argument is negative'); %# end dfdy = zeros (6, 6); r11 = 4 * k1 * y(1)^3 * sqrt (y(2)); r12 = 0.5 * k1 * y(1)^4 / sqrt (y(2)); r23 = k2 * y(4); r24 = k2 * y(3); r31 = (k2 / kbig) * y(5); r35 = (k2 / kbig) * y(1); r41 = k3 * y(4)^2; r44 = 2 * k3 * y(1) * y(4); r52 = 0.5 * k4 * y(6)^2 / sqrt (y(2)); r56 = 2 * k4 * y(6) * sqrt (y(2)); fin2 = -kla; dfdy(1,1) = -2 * r11 - r31 - r41; dfdy(1,2) = -2 * r12; dfdy(1,3) = r23; dfdy(1,4) = r24 - r44; dfdy(1,5) = -r35; dfdy(2,1) = -0.5 * r11 - r41; dfdy(2,2) = -0.5 * r12 - 0.5 * r52 + fin2; dfdy(2,4) = -r44; dfdy(2,6) = -0.5 * r56; dfdy(3,1) = r11 + r31; dfdy(3,2) = r12; dfdy(3,3) = -r23; dfdy(3,4) = -r24; dfdy(3,5) = r35; dfdy(4,1) = r31 - 2 * r41; dfdy(4,3) = -r23; dfdy(4,4) = -r24 - 2 * r44; dfdy(4,5) = r35; dfdy(5,1) = -r31; dfdy(5,2) = r52; dfdy(5,3) = r23; dfdy(5,4) = r24; dfdy(5,5) = -r35; dfdy(5,6) = r56; dfdy(6,1) = ks * y(4); dfdy(6,4) = ks * y(1); dfdy(6,6) = -1; %# Returns the MASS matrix for the chemical AKZO problem function mass = odepkg_testsuite_chemakzomass (t, y, varargin) mass = [ 1, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0; 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 0 ]; %# Returns the REFERENCE values for the chemical AKZO problem function y = odepkg_testsuite_chemakzoref () y(1,1) = 0.11507949206617e+0; y(2,1) = 0.12038314715677e-2; y(3,1) = 0.16115628874079e+0; y(4,1) = 0.36561564212492e-3; y(5,1) = 0.17080108852644e-1; y(6,1) = 0.48735313103074e-2; %!demo %! vsolver = {@odebda, @oders, @ode2r, @ode5r, @odesx}; %! for vcnt=1:length (vsolver) %! vakzo{vcnt,1} = odepkg_testsuite_chemakzo (vsolver{vcnt}, 1e-7); %! end %! vakzo %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_hires.m0000644000176000010400000001336511714561373021135 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_hires (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the HIRES testsuite of ordinary differential equations after solving (ODE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_hires %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_hires (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_hires'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2}; %# The value for the absolute tolerance vret{4} = vret{2} * 10^(-2); %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite HIRES, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 321.8122; %# The point of time when solving is stoped vinit = odepkg_testsuite_hiresinit; %# The initial values vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_hiresjac, 'MaxStep', vstop-vstart); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_hiresfun, ... [vstart, vstop], vinit, vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_hiresref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Returns the results for the HIRES problem function f = odepkg_testsuite_hiresfun (t, y, varargin) f(1,1) = -1.71 * y(1) + 0.43 * y(2) + 8.32 * y(3) + 0.0007; f(2,1) = 1.71 * y(1) - 8.75 * y(2); f(3,1) = -10.03 * y(3) + 0.43 * y(4) + 0.035 * y(5); f(4,1) = 8.32 * y(2) + 1.71 * y(3) - 1.12 * y(4); f(5,1) = -1.745 * y(5) + 0.43 * (y(6) + y(7)); f(6,1) = -280 * y(6) * y(8) + 0.69 * y(4) + 1.71 * y(5) - 0.43 * y(6) + 0.69 * y(7); f(7,1) = 280 * y(6) * y(8) - 1.81 * y(7); f(8,1) = -f(7); %# Returns the INITIAL values for the HIRES problem function vinit = odepkg_testsuite_hiresinit () vinit = [1, 0, 0, 0, 0, 0, 0, 0.0057]; %# Returns the JACOBIAN matrix for the HIRES problem function dfdy = odepkg_testsuite_hiresjac (t, y, varargin) dfdy(1,1) = -1.71; dfdy(1,2) = 0.43; dfdy(1,3) = 8.32; dfdy(2,1) = 1.71; dfdy(2,2) = -8.75; dfdy(3,3) = -10.03; dfdy(3,4) = 0.43; dfdy(3,5) = 0.035; dfdy(4,2) = 8.32; dfdy(4,3) = 1.71; dfdy(4,4) = -1.12; dfdy(5,5) = -1.745; dfdy(5,6) = 0.43; dfdy(5,7) = 0.43; dfdy(6,4) = 0.69; dfdy(6,5) = 1.71; dfdy(6,6) = -280 * y(8) - 0.43; dfdy(6,7) = 0.69; dfdy(6,8) = -280 * y(6); dfdy(7,6) = 280 * y(8); dfdy(7,7) = -1.81; dfdy(7,8) = 280 * y(6); dfdy(8,6) = -280 * y(8); dfdy(8,7) = 1.81; dfdy(8,8) = -280 * y(6); %# Returns the REFERENCE values for the HIRES problem function y = odepkg_testsuite_hiresref () y(1,1) = 0.73713125733256e-3; y(2,1) = 0.14424857263161e-3; y(3,1) = 0.58887297409675e-4; y(4,1) = 0.11756513432831e-2; y(5,1) = 0.23863561988313e-2; y(6,1) = 0.62389682527427e-2; y(7,1) = 0.28499983951857e-2; y(8,1) = 0.28500016048142e-2; %!demo %! vsolver = {@ode23, @ode45, @ode54, @ode78, ... %! @odebda, @oders, @ode2r, @ode5r, @odesx}; %! for vcnt=1:length (vsolver) %! vhires{vcnt,1} = odepkg_testsuite_hires (vsolver{vcnt}, 1e-7); %! end %! vhires %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_implakzo.m0000644000176000010400000001642111714561373021645 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_implakzo (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the chemical AKZO Nobel testsuite of implicit differential algebraic equations after solving (IDE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_implakzo %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_implakzo (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_implakzo'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2}; %# The value for the absolute tolerance vret{4} = vret{2}; %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite AKZO, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 180.0; %# The point of time when solving is stoped [vinity, vinityd] = odepkg_testsuite_implakzoinit; %# The initial values vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_implakzojac, 'MaxStep', vstop-vstart); %# ,'OutputFcn', @odeplot, 'MaxStep', 1); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_implakzofun, ... [vstart, vstop], vinity, vinityd', vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_implakzoref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Return the results for the for the chemical AKZO problem function res = odepkg_testsuite_implakzofun (t, y, yd, varargin) k1 = 18.7; k2 = 0.58; k3 = 0.09; k4 = 0.42; kbig = 34.4; kla = 3.3; ks = 115.83; po2 = 0.9; hen = 737; r1 = k1 * y(1)^4 * sqrt (y(2)); r2 = k2 * y(3) * y(4); r3 = k2 / kbig * y(1) * y(5); r4 = k3 * y(1) * y(4)^2; r5 = k4 * y(6)^2 * sqrt (y(2)); fin = kla * (po2 / hen - y(2)); res(1,1) = -2 * r1 + r2 - r3 - r4 - yd(1); res(2,1) = -0.5 * r1 - r4 - 0.5 * r5 + fin - yd(2); res(3,1) = r1 - r2 + r3 - yd(3); res(4,1) = - r2 + r3 - 2 * r4 - yd(4); res(5,1) = r2 - r3 + r5 - yd(5); res(6,1) = ks * y(1) * y(4) - y(6) - yd(6); %# Return the INITIAL values for the chemical AKZO problem function [y0, yd0] = odepkg_testsuite_implakzoinit () y0 = [0.444, 0.00123, 0, 0.007, 0, 115.83 * 0.444 * 0.007]; yd0 = [-0.051, -0.014, 0.025, 0, 0.002, 0]; %# Return the JACOBIAN matrix for the chemical AKZO problem function [dfdy, dfdyd] = odepkg_testsuite_implakzojac (t, y, varargin) k1 = 18.7; k2 = 0.58; k3 = 0.09; k4 = 0.42; kbig = 34.4; kla = 3.3; ks = 115.83; po2 = 0.9; hen = 737; %# if (y(2) <= 0) %# error ('odepkg_testsuite_implakzojac: Second input argument is negative'); %# end dfdy = zeros (6, 6); r11 = 4 * k1 * y(1)^3 * sqrt (y(2)); r12 = 0.5 * k1 * y(1)^4 / sqrt (y(2)); r23 = k2 * y(4); r24 = k2 * y(3); r31 = (k2 / kbig) * y(5); r35 = (k2 / kbig) * y(1); r41 = k3 * y(4)^2; r44 = 2 * k3 * y(1) * y(4); r52 = 0.5 * k4 * y(6)^2 / sqrt (y(2)); r56 = 2 * k4 * y(6) * sqrt (y(2)); fin2 = -kla; dfdy(1,1) = -2 * r11 - r31 - r41; dfdy(1,2) = -2 * r12; dfdy(1,3) = r23; dfdy(1,4) = r24 - r44; dfdy(1,5) = -r35; dfdy(2,1) = -0.5 * r11 - r41; dfdy(2,2) = -0.5 * r12 - 0.5 * r52 + fin2; dfdy(2,4) = -r44; dfdy(2,6) = -0.5 * r56; dfdy(3,1) = r11 + r31; dfdy(3,2) = r12; dfdy(3,3) = -r23; dfdy(3,4) = -r24; dfdy(3,5) = r35; dfdy(4,1) = r31 - 2 * r41; dfdy(4,3) = -r23; dfdy(4,4) = -r24 - 2 * r44; dfdy(4,5) = r35; dfdy(5,1) = -r31; dfdy(5,2) = r52; dfdy(5,3) = r23; dfdy(5,4) = r24; dfdy(5,5) = -r35; dfdy(5,6) = r56; dfdy(6,1) = ks * y(4); dfdy(6,4) = ks * y(1); dfdy(6,6) = -1; dfdyd = - [ 1, 0, 0, 0, 0, 0; 0, 1, 0, 0, 0, 0; 0, 0, 1, 0, 0, 0; 0, 0, 0, 1, 0, 0; 0, 0, 0, 0, 1, 0; 0, 0, 0, 0, 0, 1 ]; %# For the implicit form of the chemical AKZO Nobel problem a mass %# matrix is not needed. This mass matrix is needed if the problem %# is formulated in explicit form (cf. odepkg_testsuite_cemakzo.m). %# function mass = odepkg_testsuite_implakzomass (t, y, varargin) %# mass = [ 1, 0, 0, 0, 0, 0; %# 0, 1, 0, 0, 0, 0; %# 0, 0, 1, 0, 0, 0; %# 0, 0, 0, 1, 0, 0; %# 0, 0, 0, 0, 1, 0; %# 0, 0, 0, 0, 0, 0 ]; %# Return the REFERENCE values for the chemical AKZO problem function y = odepkg_testsuite_implakzoref () y(1,1) = 0.11507949206617e+0; y(2,1) = 0.12038314715677e-2; y(3,1) = 0.16115628874079e+0; y(4,1) = 0.36561564212492e-3; y(5,1) = 0.17080108852644e-1; y(6,1) = 0.48735313103074e-2; %!demo %! vsolver = {@odebdi}; %! for vcnt=1:length (vsolver) %! vakzo{vcnt,1} = odepkg_testsuite_implakzo (vsolver{vcnt}, 1e-7); %! end %! vakzo %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_implrober.m0000644000176000010400000001376211714561373022017 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_implrober (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the implicit form of the modified ROBERTSON testsuite of implicit differential algebraic equations after solving (IDE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_implrober %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_implrober (vhandle, vrtol) %# Check number and types of all input arguments if (nargin ~= 2) help ('odepkg_testsuite_implrober'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2} * 1e-2; %# The value for the absolute tolerance vret{4} = vret{2}; %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all present solvers fprintf (1, ['Testsuite implicit ROBERTSON, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithm options vstart = 0; %# The point of time when solving is started vstop = 1e11; %# The point of time when solving is stoped [vinity, vinityd] = odepkg_testsuite_implroberinit; %# The initial values vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_implroberjac, 'MaxStep', vstop-vstart); %# 'OutputFcn', @odeplot); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_implroberfun, ... [vstart, vstop], vinity, vinityd', vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_implroberref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %#function odepkg_testsuite_implrober () %# A = odeset ('RelTol', 1e-4, ... %# proprietary ode15i needs 1e-6 to be stable %# 'AbsTol', [1e-6, 1e-10, 1e-6], ... %# 'Jacobian', @odepkg_testsuite_implroberjac); %# [y0, yd0] = odepkg_testsuite_implroberinit; %# odebdi (@odepkg_testsuite_implroberfun, [0, 1e11], y0, yd0', A) %# [y0, yd0] = odepkg_testsuite_implroberinit; %# odebdi (@odepkg_testsuite_implroberfun, [0, 1e11], y0, yd0') %# Return the results for the for the implicit ROBERTSON problem function res = odepkg_testsuite_implroberfun (t, y, yd, varargin) res(1,1) = -0.04 * y(1) + 1e4 * y(2) * y(3) - yd(1); res(2,1) = 0.04 * y(1) - 1e4 * y(2) * y(3) - 3e7 * y(2)^2 - yd(2); res(3,1) = y(1) + y(2) + y(3) - 1; %# Return the INITIAL values for the implicit ROBERTSON problem function [y0, yd0] = odepkg_testsuite_implroberinit () y0 = [1, 0, 0]; yd0 = [-4e-2, 4e-2, 0]; %# Return the JACOBIAN matrix for the implicit ROBERTSON problem function [dfdy, dfdyd] = odepkg_testsuite_implroberjac (t, y, yd, varargin) dfdy(1,1) = -0.04; dfdy(1,2) = 1e4 * y(3); dfdy(1,3) = 1e4 * y(2); dfdy(2,1) = 0.04; dfdy(2,2) = -1e4 * y(3) - 6e7 * y(2); dfdy(2,3) = -1e4 * y(2); dfdy(3,1) = 1; dfdy(3,2) = 1; dfdy(3,3) = 1; dfdyd(1,1) = -1; dfdyd(2,2) = -1; dfdyd(3,3) = 0; %# For the implicit form of the Robertson problem a mass matrix is not %# allowed. This mass matrix is only needed if the Robertson problem %# is formulated in explicit form (cf. odepkg_testsuite_implrober.m). %# function mass = odepkg_testsuite_implrobermass (t, y, varargin) %# mass = [1, 0, 0; 0, 1, 0; 0, 0, 0]; %# Return the REFERENCE values for the implicit ROBERTSON problem function y = odepkg_testsuite_implroberref () y(1) = 0.20833401497012e-07; y(2) = 0.83333607703347e-13; y(3) = 0.99999997916650e+00; %!demo %! vsolver = {@odebdi}; %! for vcnt=1:length (vsolver) %! virob{vcnt,1} = odepkg_testsuite_implrober (vsolver{vcnt}, 1e-7); %! end %! virob %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_impltrans.m0000644000176000010400000001775511714561373022043 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_impltrans (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return the cell array @var{solution} with performance informations about the TRANSISTOR testsuite of implicit differential algebraic equations after solving (IDE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_impltrans %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_impltrans (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_impltrans'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2}; %# The value for the absolute tolerance vret{4} = vret{2}; %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite TRANSISTOR, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 0.2; %# The point of time when solving is stoped [vinity, vinityd] = odepkg_testsuite_impltransinit; %# The initial values vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_impltransjac, 'MaxStep', vstop-vstart); %# ,'OutputFcn', @odeplot, 'MaxStep', 1e-4); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_impltransfun, ... [vstart, vstop], vinity, vinityd', vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_impltransref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Returns the results for the implicit TRANSISTOR problem function res = odepkg_testsuite_impltransfun (t, y, yd, varargin) ub = 6; uf = 0.026; alpha = 0.99; beta = 1e-6; r0 = 1000; r1 = 9000; r2 = 9000; r3 = 9000; r4 = 9000; r5 = 9000; r6 = 9000; r7 = 9000; r8 = 9000; r9 = 9000; c1 = 1e-6; c2 = 2e-6; c3 = 3e-6; c4 = 4e-6; c5 = 5e-6; uet = 0.1 * sin(200 * pi * t); fac1 = beta * (exp((y(2) - y(3)) / uf) - 1); fac2 = beta * (exp((y(5) - y(6)) / uf) - 1); res(1,1) = (y(1) - uet) / r0 + c1 * yd(1) - c1 * yd(2); res(2,1) = y(2) / r1 + (y(2) - ub) / r2 + (1 - alpha) * fac1 - c1 * yd(1) + c1 * yd(2); res(3,1) = y(3) / r3 - fac1 + c2 * yd(3); res(4,1) = (y(4) - ub) / r4 + alpha * fac1 + c3 * yd(4) - c3 * yd(5); res(5,1) = y(5) / r5 + (y(5) - ub) / r6 + (1 - alpha) * fac2 - c3 * yd(4) + c3 * yd(5); res(6,1) = y(6) / r7 - fac2 + c4 * yd(6); res(7,1) = (y(7) - ub) / r8 + alpha * fac2 + c5 * yd(7) - c5 * yd(8); res(8,1) = y(8) / r9 - c5 * yd(7) + c5 * yd(8); %# Returns the INITIAL values for the TRANSISTOR problem function [y0, yd0] = odepkg_testsuite_impltransinit () y0 = [0, 3, 3, 6, 3, 3, 6, 0]; yd0 = 1e-3 * [0, 0, 1/3, 0, 0, 1/3, 0, 0]; %# yd0 = [ 51.338775, 51.338775, -166.666666, -24.975766, ... %# -24.975766, -83.333333, -10.0056445, -10.005644]; %# Returns the JACOBIAN matrix for the TRANSISTOR problem function [dfdy, dfdyd] = odepkg_testsuite_impltransjac (t, y, varargin) ub = 6; uf = 0.026; alpha = 0.99; beta = 1e-6; r0 = 1000; r1 = 9000; r2 = 9000; r3 = 9000; r4 = 9000; r5 = 9000; r6 = 9000; r7 = 9000; r8 = 9000; r9 = 9000; c1 = 1e-6; c2 = 2e-6; c3 = 3e-6; c4 = 4e-6; c5 = 5e-6; fac1p = beta * exp ((y(2) - y(3)) / uf) / uf; fac2p = beta * exp ((y(5) - y(6)) / uf) / uf; dfdy(1,1) = 1 / r0; dfdy(2,2) = 1 / r1 + 1 / r2 + (1 - alpha) * fac1p; dfdy(2,3) = - (1 - alpha) * fac1p; dfdy(3,2) = - fac1p; dfdy(3,3) = 1 / r3 + fac1p; dfdy(4,2) = alpha * fac1p; dfdy(4,3) = - alpha * fac1p; dfdy(4,4) = 1 / r4; dfdy(5,5) = 1 / r5 + 1 / r6 + (1 - alpha) * fac2p; dfdy(5,6) = - (1 - alpha) * fac2p; dfdy(6,5) = - fac2p; dfdy(6,6) = 1 / r7 + fac2p; dfdy(7,5) = alpha * fac2p; dfdy(7,6) = - alpha * fac2p; dfdy(7,7) = 1 / r8; dfdy(8,8) = 1 / r9; dfdyd = [ c1, -c1, 0, 0, 0, 0, 0, 0; ... -c1, c1, 0, 0, 0, 0, 0, 0; ... 0, 0, c2, 0, 0, 0, 0, 0; ... 0, 0, 0, c3, -c3, 0, 0, 0; ... 0, 0, 0, -c3, c3, 0, 0, 0; ... 0, 0, 0, 0, 0, c4, 0, 0; ... 0, 0, 0, 0, 0, 0, c5, -c5; ... 0, 0, 0, 0, 0, 0, -c5, c5]; %# For the implicit form of the TRANSISTOR problem a mass matrix is %# not needed. This mass matrix is needed if the problem is formulated %# in explicit form (cf. odepkg_testsuite_transistor.m). %# function mass = odepkg_testsuite_impltransmass (t, y, varargin) %# mass = [-1e-6, 1e-6, 0, 0, 0, 0, 0, 0; ... %# 1e-6, -1e-6, 0, 0, 0, 0, 0, 0; ... %# 0, 0, -2e-6, 0, 0, 0, 0, 0; ... %# 0, 0, 0, -3e-6, 3e-6, 0, 0, 0; ... %# 0, 0, 0, 3e-6, -3e-6, 0, 0, 0; ... %# 0, 0, 0, 0, 0, -4e-6, 0, 0; ... %# 0, 0, 0, 0, 0, 0, -5e-6, 5e-6; ... %# 0, 0, 0, 0, 0, 0, 5e-6, -5e-6]; %# Returns the REFERENCE values for the TRANSISTOR problem function y = odepkg_testsuite_impltransref () y(1,1) = -0.55621450122627e-2; y(2,1) = 0.30065224719030e+1; y(3,1) = 0.28499587886081e+1; y(4,1) = 0.29264225362062e+1; y(5,1) = 0.27046178650105e+1; y(6,1) = 0.27618377783931e+1; y(7,1) = 0.47709276316167e+1; y(8,1) = 0.12369958680915e+1; %!demo %! vsolver = {@odebdi}; %! for vcnt=1:length (vsolver) %! vtrans{vcnt,1} = odepkg_testsuite_impltrans (vsolver{vcnt}, 1e-7); %! end %! vtrans %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_oregonator.m0000644000176000010400000001233411714561373022175 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_oregonator (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the OREGONATOR testsuite of ordinary differential equations after solving (ODE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_oregonator %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_oregonator (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_oregonator'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) usage ('odepkg_testsuite_oregonator (@solver, reltol)'); end vret{1} = vhandle; %# The name for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2}; %# The value for the absolute tolerance vret{4} = vret{2} * 10^(-2); %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite OREGONATOR, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 360.0; %# The point of time when solving is stoped vinit = odepkg_testsuite_oregonatorinit; %# The initial values vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_oregonatorjac, 'MaxStep', vstop-vstart); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_oregonatorfun, ... [vstart, vstop], vinit, vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_oregonatorref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Returns the results for the OREGONATOR problem function f = odepkg_testsuite_oregonatorfun (t, y, varargin) f(1,1) = 77.27 * (y(2) + y(1) * (1.0 - 8.375e-6 * y(1) - y(2))); f(2,1) = (y(3) - (1.0 + y(1)) * y(2)) / 77.27; f(3,1) = 0.161 * (y(1) - y(3)); %# Returns the INITIAL values for the OREGONATOR problem function vinit = odepkg_testsuite_oregonatorinit () vinit = [1, 2, 3]; %# Returns the JACOBIAN matrix for the OREGONATOR problem function dfdy = odepkg_testsuite_oregonatorjac (t, y, varargin) dfdy(1,1) = 77.27 * (1.0 - 2.0 * 8.375e-6 * y(1) - y(2)); dfdy(1,2) = 77.27 * (1.0 - y(1)); dfdy(1,3) = 0.0; dfdy(2,1) = -y(2) / 77.27; dfdy(2,2) = -(1.0 + y(1)) / 77.27; dfdy(2,3) = 1.0 / 77.27; dfdy(3,1) = 0.161; dfdy(3,2) = 0.0; dfdy(3,3) = -0.161; %# Returns the REFERENCE values for the OREGONATOR problem function y = odepkg_testsuite_oregonatorref () y(1,1) = 0.10008148703185e+1; y(1,2) = 0.12281785215499e+4; y(1,3) = 0.13205549428467e+3; %!demo %! %% vsolver = {@ode23, @ode45, @ode54, @ode78, ... %! %% @odebda, @oders, @ode2r, @ode5r, @odesx}; %! vsolver = {@odebda, @oders, @ode2r, @ode5r, @odesx}; %! for vcnt=1:length (vsolver) %! voreg{vcnt,1} = odepkg_testsuite_oregonator (vsolver{vcnt}, 1e-7); %! end %! voreg %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_pollution.m0000644000176000010400000002455011714561373022046 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_pollution (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return the cell array @var{solution} with performance informations about the POLLUTION testsuite of ordinary differential equations after solving (ODE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_pollution %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_pollution (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_pollution'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2}; %# The value for the absolute tolerance vret{4} = vret{2}; %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite POLLUTION, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 60.0; %# The point of time when solving is stoped vinit = odepkg_testsuite_pollutioninit; %# The initial values vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_pollutionjac, 'MaxStep', vstop-vstart); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_pollutionfun, ... [vstart, vstop], vinit, vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_pollutionref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Returns the results for the for the POLLUTION problem function f = odepkg_testsuite_pollutionfun (t, y, varargin) f(01,1) = - 0.350 * y(1) + 0.266e2 * y(2) * y(4) + 0.123e5 * y(2) * y(5) + ... 0.165e5 * y(2) * y(11) - 0.900e4 * y(1) * y(11) + 0.220e-1 * y(13) + ... 0.120e5 * y(2) * y(10) - 0.163e5 * y(1) * y(6) + 0.578e1 * y(19) - ... 0.474e-1 * y(1) * y(4) - 0.178e4 * y(1) * y(19) + 0.312e1 * y(20); f(02,1) = + 0.350 * y(1) - 0.266e2 * y(2) * y(4) - 0.123e5 * y(2) * y(5) - ... 0.165e5 * y(2) * y(11) - 0.120e5 * y(2) * y(10) + 0.210e1 * y(19); f(03,1) = + 0.350 * y(1) - 0.480e7 * y(3) + 0.175e-1 * y(4) + 0.444e12 * y(16) + 0.578e1 * y(19); f(04,1) = - 0.266e2 * y(2) * y(4) + 0.480e7 * y(3) - 0.350e-3 * y(4) - ... 0.175e-1 * y(4) - 0.474e-1 * y(1) * y(4); f(05,1) = - 0.123e5 * y(2) * y(5) + 2*0.860e-3 * y(7) + 0.150e5 * y(6) * y(7) + ... 0.130e-3 * y(9) + 0.188e1 * y(14) + 0.124e4 * y(6) * y(17); f(06,1) = + 0.123e5 * y(2) * y(5) - 0.150e5 * y(6) * y(7) - 0.240e5 * y(6) * y(9) - ... 0.163e5 * y(1) * y(6) + 2*0.100e9 * y(16) - 0.124e4 * y(6) * y(17); f(07,1) = - 0.860e-3 * y(7) - 0.820e-3 * y(7) - 0.150e5 * y(6) * y(7) + 0.188e1 * y(14); f(08,1) = + 0.860e-3 * y(7) + 0.820e-3 * y(7) + 0.150e5 * y(6) * y(7) + 0.130e-3 * y(9); f(09,1) = - 0.130e-3 * y(9) - 0.240e5 * y(6) * y(9); f(10,1) = + 0.130e-3 * y(9) + 0.165e5 * y(2) * y(11) - 0.120e5 * y(2) * y(10); f(11,1) = + 0.240e5 * y(6) * y(9) - 0.165e5 * y(2) * y(11) - 0.900e4 * y(1) * y(11) + ... 0.220e-1 * y(13); f(12,1) = + 0.165e5 * y(2) * y(11); f(13,1) = + 0.900e4 * y(1) * y(11) - 0.220e-1 * y(13); f(14,1) = + 0.120e5 * y(2) * y(10) - 0.188e1 * y(14); f(15,1) = + 0.163e5 * y(1) * y(6); f(16,1) = + 0.350e-3 * y(4) - 0.100e9 * y(16) - 0.444e12 * y(16); f(17,1) = - 0.124e4 * y(6) * y(17); f(18,1) = + 0.124e4 * y(6) * y(17); f(19,1) = - 0.210e1 * y(19) - 0.578e1 * y(19) + 0.474e-1 * y(1) * y(4) - ... 0.178e4 * y(1) * y(19) + 0.312e1 * y(20); f(20,1) = + 0.178e4 * y(1) * y(19) - 0.312e1 * y(20); %# Returns the INITIAL values for the POLLUTION problem function vinit = odepkg_testsuite_pollutioninit () vinit = [0, 0.2, 0, 0.04, 0, 0, 0.1, 0.3, 0.01, ... 0, 0, 0, 0, 0, 0, 0, 0.007, 0, 0, 0]; %# Returns the JACOBIAN matrix for the POLLUTION problem function dfdy = odepkg_testsuite_pollutionjac (t, y) k1 = 0.35e0; k2 = 0.266e2; k3 = 0.123e5; k4 = 0.86e-3; k5 = 0.82e-3; k6 = 0.15e5; k7 = 0.13e-3; k8 = 0.24e5; k9 = 0.165e5; k10 = 0.9e4; k11 = 0.22e-1; k12 = 0.12e5; k13 = 0.188e1; k14 = 0.163e5; k15 = 0.48e7; k16 = 0.35e-3; k17 = 0.175e-1; k18 = 0.1e9; k19 = 0.444e12; k20 = 0.124e4; k21 = 0.21e1; k22 = 0.578e1; k23 = 0.474e-1; k24 = 0.178e4; k25 = 0.312e1; dfdy(1,1) = -k1 - k10 * y(11) - k14 * y(6) - k23 * y(4) - k24 * y(19); dfdy(1,11) = -k10 * y(1) + k9 * y(2); dfdy(1,6) = -k14 * y(1); dfdy(1,4) = -k23 * y(1) + k2 * y(2); dfdy(1,19) = -k24 * y(1) + k22; dfdy(1,2) = k2 * y(4) + k9 * y(11) + k3 * y(5) + k12 * y(10); dfdy(1,13) = k11; dfdy(1,20) = k25; dfdy(1,5) = k3 * y(2); dfdy(1,10) = k12 * y(2); dfdy(2,4) = -k2 * y(2); dfdy(2,5) = -k3 * y(2); dfdy(2,11) = -k9 * y(2); dfdy(2,10) = -k12 * y(2); dfdy(2,19) = k21; dfdy(2,1) = k1; dfdy(2,2) = -k2 * y(4) - k3 * y(5) - k9 * y(11) - k12 * y(10); dfdy(3,1) = k1; dfdy(3,4) = k17; dfdy(3,16) = k19; dfdy(3,19) = k22; dfdy(3,3) = -k15; dfdy(4,4) = -k2 * y(2) - k16 - k17 - k23 * y(1); dfdy(4,2) = -k2 * y(4); dfdy(4,1) = -k23 * y(4); dfdy(4,3) = k15; dfdy(5,5) = -k3 * y(2); dfdy(5,2) = -k3 * y(5); dfdy(5,7) = 2d0 * k4 + k6 * y(6); dfdy(5,6) = k6 * y(7) + k20 * y(17); dfdy(5,9) = k7; dfdy(5,14) = k13; dfdy(5,17) = k20 * y(6); dfdy(6,6) = -k6 * y(7) - k8 * y(9) - k14 * y(1) - k20 * y(17); dfdy(6,7) = -k6 * y(6); dfdy(6,9) = -k8 * y(6); dfdy(6,1) = -k14 * y(6); dfdy(6,17) = -k20 * y(6); dfdy(6,2) = k3 * y(5); dfdy(6,5) = k3 * y(2); dfdy(6,16) = 2d0 * k18; dfdy(7,7) = -k4 - k5 - k6 * y(6); dfdy(7,6) = -k6 * y(7); dfdy(7,14) = k13; dfdy(8,7) = k4 + k5 + k6 * y(6); dfdy(8,6) = k6 * y(7); dfdy(8,9) = k7; dfdy(9,9) = -k7 - k8 * y(6); dfdy(9,6) = -k8 * y(9); dfdy(10,10) = -k12 * y(2); dfdy(10,2) = -k12 * y(10) + k9 * y(11); dfdy(10,9) = k7; dfdy(10,11) = k9 * y(2); dfdy(11,11) = -k9 * y(2) - k10 * y(1); dfdy(11,2) = -k9 * y(11); dfdy(11,1) = -k10 * y(11); dfdy(11,9) = k8 * y(6); dfdy(11,6) = k8 * y(9); dfdy(11,13) = k11; dfdy(12,11) = k9 * y(2); dfdy(12,2) = k9 * y(11); dfdy(13,13) = -k11; dfdy(13,11) = k10 * y(1); dfdy(13,1) = k10 * y(11); dfdy(14,14) = -k13; dfdy(14,10) = k12 * y(2); dfdy(14,2) = k12 * y(10); dfdy(15,1) = k14 * y(6); dfdy(15,6) = k14 * y(1); dfdy(16,16) = -k18 - k19; dfdy(16,4) = k16; dfdy(17,17) = -k20 * y(6); dfdy(17,6) = -k20 * y(17); dfdy(18,17) = k20 * y(6); dfdy(18,6) = k20 * y(17); dfdy(19,19) = -k21 - k22 - k24 * y(1); dfdy(19,1) = -k24 * y(19) + k23 * y(4); dfdy(19,4) = k23 * y(1); dfdy(19,20) = k25; dfdy(20,20) = -k25; dfdy(20,1) = k24 * y(19); dfdy(20,19) = k24 * y(1); %# Returns the REFERENCE values for the POLLUTION problem function y = odepkg_testsuite_pollutionref () y(01,1) = 0.56462554800227 * 10^(-1); y(02,1) = 0.13424841304223 * 10^(+0); y(03,1) = 0.41397343310994 * 10^(-8); y(04,1) = 0.55231402074843 * 10^(-2); y(05,1) = 0.20189772623021 * 10^(-6); y(06,1) = 0.20189772623021 * 10^(-6); y(07,1) = 0.77842491189979 * 10^(-1); y(08,1) = 0.77842491189979 * 10^(+0); y(09,1) = 0.74940133838804 * 10^(-2); y(10,1) = 0.16222931573015 * 10^(-7); y(11,1) = 0.11358638332570 * 10^(-7); y(12,1) = 0.22305059757213 * 10^(-2); y(13,1) = 0.20871628827986 * 10^(-3); y(14,1) = 0.13969210168401 * 10^(-4); y(15,1) = 0.89648848568982 * 10^(-2); y(16,1) = 0.43528463693301 * 10^(-17); y(17,1) = 0.68992196962634 * 10^(-2); y(18,1) = 0.10078030373659 * 10^(-3); y(19,1) = 0.17721465139699 * 10^(-5); y(20,1) = 0.56829432923163 * 10^(-4); %!demo %! %% vsolver = {@ode23, @ode45, @ode54, @ode78, ... %! %% @odebda, @oders, @ode2r, @ode5r, @odesx}; %! vsolver = {@odebda, @oders, @ode2r, @ode5r, @odesx}; %! for vcnt=1:length (vsolver) %! poll{vcnt,1} = odepkg_testsuite_pollution (vsolver{vcnt}, 1e-7); %! end %! poll %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_robertson.m0000644000176000010400000001244011714561373022031 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_robertson (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return a cell array @var{solution} with performance informations about the modified ROBERTSON testsuite of differential algebraic equations after solving (DAE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_robertson %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_robertson (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_robertson'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2} * 1e-2; %# The value for the absolute tolerance vret{4} = vret{2}; %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite ROBERTSON, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 1e11; %# The point of time when solving is stoped vinit = odepkg_testsuite_robertsoninit; %# The initial values vmass = odepkg_testsuite_robertsonmass; %# The mass matrix vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_robertsonjac, 'Mass', vmass, ... 'MaxStep', vstop-vstart); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_robertsonfun, ... [vstart, vstop], vinit, vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_robertsonref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Returns the results for the for the modified ROBERTSON problem function f = odepkg_testsuite_robertsonfun (t, y, varargin) f(1,1) = -0.04 * y(1) + 1e4 * y(2) * y(3); f(2,1) = 0.04 * y(1) - 1e4 * y(2) * y(3) - 3e7 * y(2)^2; f(3,1) = y(1) + y(2) + y(3) - 1; %# Returns the INITIAL values for the modified ROBERTSON problem function vinit = odepkg_testsuite_robertsoninit () vinit = [1, 0, 0]; %# Returns the JACOBIAN matrix for the modified ROBERTSON problem function dfdy = odepkg_testsuite_robertsonjac (t, y, varargin) dfdy(1,1) = -0.04; dfdy(1,2) = 1e4 * y(3); dfdy(1,3) = 1e4 * y(2); dfdy(2,1) = 0.04; dfdy(2,2) = -1e4 * y(3) - 6e7 * y(2); dfdy(2,3) = -1e4 * y(2); dfdy(3,1) = 1; dfdy(3,2) = 1; dfdy(3,3) = 1; %# Returns the MASS matrix for the modified ROBERTSON problem function mass = odepkg_testsuite_robertsonmass (t, y, varargin) mass = [1, 0, 0; 0, 1, 0; 0, 0, 0]; %# Returns the REFERENCE values for the modified ROBERTSON problem function y = odepkg_testsuite_robertsonref () y(1) = 0.20833401497012e-07; y(2) = 0.83333607703347e-13; y(3) = 0.99999997916650e+00; %!demo %! vsolver = {@odebda, @oders, @ode2r, @ode5r, @odesx}; %! for vcnt=1:length (vsolver) %! vrober{vcnt,1} = odepkg_testsuite_robertson (vsolver{vcnt}, 1e-7); %! end %! vrober %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odepkg_testsuite_transistor.m0000644000176000010400000001572011714561373022230 0ustar marcoAdministrators%# Copyright (C) 2007-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{solution}] =} odepkg_testsuite_transistor (@var{@@solver}, @var{reltol}) %# %# If this function is called with two input arguments and the first input argument @var{@@solver} is a function handle describing an OdePkg solver and the second input argument @var{reltol} is a double scalar describing the relative error tolerance then return the cell array @var{solution} with performance informations about the TRANSISTOR testsuite of differential algebraic equations after solving (DAE--test). %# %# Run examples with the command %# @example %# demo odepkg_testsuite_transistor %# @end example %# %# This function has been ported from the "Test Set for IVP solvers" which is developed by the INdAM Bari unit project group "Codes and Test Problems for Differential Equations", coordinator F. Mazzia. %# @end deftypefn %# %# @seealso{odepkg} function vret = odepkg_testsuite_transistor (vhandle, vrtol) if (nargin ~= 2) %# Check number and types of all input arguments help ('odepkg_testsuite_transistor'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be exactly two'); elseif (~isa (vhandle, 'function_handle') || ~isscalar (vrtol)) print_usage; end vret{1} = vhandle; %# The handle for the solver that is used vret{2} = vrtol; %# The value for the realtive tolerance vret{3} = vret{2}; %# The value for the absolute tolerance vret{4} = vret{2}; %# The value for the first time step %# Write a debug message on the screen, because this testsuite function %# may be called more than once from a loop over all solvers present fprintf (1, ['Testsuite TRANSISTOR, testing solver %7s with relative', ... ' tolerance %2.0e\n'], func2str (vret{1}), vrtol); fflush (1); %# Setting the integration algorithms option values vstart = 0.0; %# The point of time when solving is started vstop = 0.2; %# The point of time when solving is stoped vinit = odepkg_testsuite_transistorinit; %# The initial values vmass = odepkg_testsuite_transistormass; %# The mass matrix vopt = odeset ('Refine', 0, 'RelTol', vret{2}, 'AbsTol', vret{3}, ... 'InitialStep', vret{4}, 'Stats', 'on', 'NormControl', 'off', ... 'Jacobian', @odepkg_testsuite_transistorjac, 'Mass', vmass, ... 'MaxStep', vstop-vstart); %# Calculate the algorithm, start timer and do solving tic; vsol = feval (vhandle, @odepkg_testsuite_transistorfun, ... [vstart, vstop], vinit, vopt); vret{12} = toc; %# The value for the elapsed time vref = odepkg_testsuite_transistorref; %# Get the reference solution vector if (exist ('OCTAVE_VERSION') ~= 0) vlst = vsol.y(end,:); else vlst = vsol.y(:,end); end vret{5} = odepkg_testsuite_calcmescd (vlst, vref, vret{3}, vret{2}); vret{6} = odepkg_testsuite_calcscd (vlst, vref, vret{3}, vret{2}); vret{7} = vsol.stats.nsteps + vsol.stats.nfailed; %# The value for all evals vret{8} = vsol.stats.nsteps; %# The value for success evals vret{9} = vsol.stats.nfevals; %# The value for fun calls vret{10} = vsol.stats.npds; %# The value for partial derivations vret{11} = vsol.stats.ndecomps; %# The value for LU decompositions %# Returns the results for the TRANSISTOR problem function f = odepkg_testsuite_transistorfun (t, y, varargin) ub = 6; uf = 0.026; alpha = 0.99; beta = 1d-6; r0 = 1000; r1 = 9000; r2 = 9000; r3 = 9000; r4 = 9000; r5 = 9000; r6 = 9000; r7 = 9000; r8 = 9000; r9 = 9000; uet = 0.1 * sin(200 * pi * t); fac1 = beta * (exp((y(2) - y(3)) / uf) - 1); fac2 = beta * (exp((y(5) - y(6)) / uf) - 1); f(1,1) = (y(1) - uet) / r0; f(2,1) = y(2) / r1 + (y(2) - ub) / r2 + (1 - alpha) * fac1; f(3,1) = y(3) / r3 - fac1; f(4,1) = (y(4) - ub) / r4 + alpha * fac1; f(5,1) = y(5) / r5 + (y(5) - ub) / r6 + (1 - alpha) * fac2; f(6,1) = y(6) / r7 - fac2; f(7,1) = (y(7) - ub) / r8 + alpha * fac2; f(8,1) = y(8) / r9; %# Returns the INITIAL values for the TRANSISTOR problem function vinit = odepkg_testsuite_transistorinit () vinit = [0, 3, 3, 6, 3, 3, 6, 0]; %# Returns the JACOBIAN matrix for the TRANSISTOR problem function dfdy = odepkg_testsuite_transistorjac (t, y, varargin) ub = 6; uf = 0.026; alpha = 0.99; beta = 1d-6; r0 = 1000; r1 = 9000; r2 = 9000; r3 = 9000; r4 = 9000; r5 = 9000; r6 = 9000; r7 = 9000; r8 = 9000; r9 = 9000; fac1p = beta * exp ((y(2) - y(3)) / uf) / uf; fac2p = beta * exp ((y(5) - y(6)) / uf) / uf; dfdy(1,1) = 1 / r0; dfdy(2,2) = 1 / r1 + 1 / r2 + (1 - alpha) * fac1p; dfdy(2,3) = - (1 - alpha) * fac1p; dfdy(3,2) = - fac1p; dfdy(3,3) = 1 / r3 + fac1p; dfdy(4,2) = alpha * fac1p; dfdy(4,3) = - alpha * fac1p; dfdy(4,4) = 1 / r4; dfdy(5,5) = 1 / r5 + 1 / r6 + (1 - alpha) * fac2p; dfdy(5,6) = - (1 - alpha) * fac2p; dfdy(6,5) = - fac2p; dfdy(6,6) = 1 / r7 + fac2p; dfdy(7,5) = alpha * fac2p; dfdy(7,6) = - alpha * fac2p; dfdy(7,7) = 1 / r8; dfdy(8,8) = 1 / r9; %# Returns the MASS matrix for the TRANSISTOR problem function mass = odepkg_testsuite_transistormass (t, y, varargin) mass = [-1e-6, 1e-6, 0, 0, 0, 0, 0, 0; ... 1e-6, -1e-6, 0, 0, 0, 0, 0, 0; ... 0, 0, -2e-6, 0, 0, 0, 0, 0; ... 0, 0, 0, -3e-6, 3e-6, 0, 0, 0; ... 0, 0, 0, 3e-6, -3e-6, 0, 0, 0; ... 0, 0, 0, 0, 0, -4e-6, 0, 0; ... 0, 0, 0, 0, 0, 0, -5e-6, 5e-6; ... 0, 0, 0, 0, 0, 0, 5e-6, -5e-6]; %# Returns the REFERENCE values for the TRANSISTOR problem function y = odepkg_testsuite_transistorref () y(1,1) = -0.55621450122627e-2; y(2,1) = 0.30065224719030e+1; y(3,1) = 0.28499587886081e+1; y(4,1) = 0.29264225362062e+1; y(5,1) = 0.27046178650105e+1; y(6,1) = 0.27618377783931e+1; y(7,1) = 0.47709276316167e+1; y(8,1) = 0.12369958680915e+1; %!demo %! vsolver = {@odebda, @oders, @ode2r, @ode5r, @odesx}; %! for vcnt=1:length (vsolver) %! vtrans{vcnt,1} = odepkg_testsuite_transistor (vsolver{vcnt}, 1e-7); %! end %! vtrans %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odeplot.m0000644000176000010400000000665511742512661016030 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{ret}] =} odeplot (@var{t}, @var{y}, @var{flag}) %# %# Open a new figure window and plot the results from the variable @var{y} of type column vector over time while solving. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is %# @table @option %# @item @code{"init"} %# then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, %# @item @code{""} %# then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', %# @item @code{"done"} %# then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. %# @end table %# %# This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. %# %# For example, solve an anonymous implementation of the "Van der Pol" equation and display the results while solving %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# %# vopt = odeset ('OutputFcn', @@odeplot, 'RelTol', 1e-6); %# vsol = ode45 (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = odeplot (vt, vy, vflag, varargin) %# No input argument check is done for a higher processing speed persistent vfigure; persistent vtold; persistent vyold; persistent vcounter; if (strcmp (vflag, 'init')) %# Nothing to return, vt is either the time slot [tstart tstop] %# or [t0, t1, ..., tn], vy is the inital value vector 'vinit' vfigure = figure; vtold = vt(1,1); vyold = vy(:,1); vcounter = 1; elseif (isempty (vflag)) %# Return something in varargout{1}, either false for 'not stopping %# the integration' or true for 'stopping the integration' vcounter = vcounter + 1; figure (vfigure); vtold(vcounter,1) = vt(1,1); vyold(:,vcounter) = vy(:,1); plot (vtold, vyold, '-o', 'markersize', 1); drawnow; varargout{1} = false; elseif (strcmp (vflag, 'done')) %# Cleanup has to be done, clear the persistent variables because %# we don't need them anymore clear ('vfigure', 'vtold', 'vyold', 'vcounter'); end %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odeprint.m0000644000176000010400000000644211742512661016200 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{ret}] =} odeprint (@var{t}, @var{y}, @var{flag}) %# %# Display the results of the set of differential equations in the Octave window while solving. The first column of the screen output shows the actual time stamp that is given with the input arguemtn @var{t}, the following columns show the results from the function evaluation that are given by the column vector @var{y}. The types and the values of the input parameter @var{t} and the output parameter @var{ret} depend on the input value @var{flag} that is of type string. If @var{flag} is %# @table @option %# @item @code{"init"} %# then @var{t} must be a double column vector of length 2 with the first and the last time step and nothing is returned from this function, %# @item @code{""} %# then @var{t} must be a double scalar specifying the actual time step and the return value is false (resp. value 0) for 'not stop solving', %# @item @code{"done"} %# then @var{t} must be a double scalar specifying the last time step and nothing is returned from this function. %# @end table %# %# This function is called by a OdePkg solver function if it was specified in an OdePkg options structure with the @command{odeset}. This function is an OdePkg internal helper function therefore it should never be necessary that this function is called directly by a user. There is only little error detection implemented in this function file to achieve the highest performance. %# %# For example, solve an anonymous implementation of the "Van der Pol" equation and print the results while solving %# @example %# fvdb = @@(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %# %# vopt = odeset ('OutputFcn', @@odeprint, 'RelTol', 1e-6); %# vsol = ode45 (fvdb, [0 20], [2 0], vopt); %# @end example %# @end deftypefn %# %# @seealso{odepkg} function [varargout] = odeprint (vt, vy, vflag, varargin) %# No input argument check is done for a higher processing speed %# vt and vy are always column vectors, see also function odeplot, %# odephas2 and odephas3 for another implementation. vflag either %# is "init", [] or "done". if (strcmp (vflag, 'init')) fprintf (1, '%f%s\n', vt (1,1), sprintf (' %f', vy) ); fflush (1); elseif (isempty (vflag)) %# Return value varargout{1} needed fprintf (1, '%f%s\n', vt (1,1), sprintf (' %f', vy) ); fflush (1); varargout{1} = false; elseif (strcmp (vflag, 'done')) %# Cleanup could be done, but nothing to do in this function end %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/inst/odeset.m0000644000176000010400000001662311711232766015642 0ustar marcoAdministrators%# Copyright (C) 2006-2012, Thomas Treichl %# OdePkg - A package for solving ordinary differential equations and more %# %# This program is free software; you can redistribute it and/or modify %# it under the terms of the GNU General Public License as published by %# the Free Software Foundation; either version 2 of the License, or %# (at your option) any later version. %# %# This program is distributed in the hope that it will be useful, %# but WITHOUT ANY WARRANTY; without even the implied warranty of %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %# GNU General Public License for more details. %# %# You should have received a copy of the GNU General Public License %# along with this program; If not, see . %# -*- texinfo -*- %# @deftypefn {Function File} {[@var{odestruct}] =} odeset () %# @deftypefnx {Command} {[@var{odestruct}] =} odeset (@var{"field1"}, @var{value1}, @var{"field2"}, @var{value2}, @dots{}) %# @deftypefnx {Command} {[@var{odestruct}] =} odeset (@var{oldstruct}, @var{"field1"}, @var{value1}, @var{"field2"}, @var{value2}, @dots{}) %# @deftypefnx {Command} {[@var{odestruct}] =} odeset (@var{oldstruct}, @var{newstruct}) %# %# If this function is called without an input argument then return a new OdePkg options structure array that contains all the necessary fields and sets the values of all fields to default values. %# %# If this function is called with string input arguments @var{"field1"}, @var{"field2"}, @dots{} identifying valid OdePkg options then return a new OdePkg options structure with all necessary fields and set the values of the fields @var{"field1"}, @var{"field2"}, @dots{} to the values @var{value1}, @var{value2}, @dots{} %# %# If this function is called with a first input argument @var{oldstruct} of type structure array then overwrite all values of the options @var{"field1"}, @var{"field2"}, @dots{} of the structure @var{oldstruct} with new values @var{value1}, @var{value2}, @dots{} and return the modified structure array. %# %# If this function is called with two input argumnets @var{oldstruct} and @var{newstruct} of type structure array then overwrite all values in the fields from the structure @var{oldstruct} with new values of the fields from the structure @var{newstruct}. Empty values of @var{newstruct} will not overwrite values in @var{oldstruct}. %# %# For a detailed explanation about valid fields and field values in an OdePkg structure aaray have a look at the @file{odepkg.pdf}, Section 'ODE/DAE/IDE/DDE options' or run the command @command{doc odepkg} to open the tutorial. %# %# Run examples with the command %# @example %# demo odeset %# @end example %# @end deftypefn %# %# @seealso{odepkg} function [vret] = odeset (varargin) %# Create a template OdePkg structure vtemplate = struct ... ('RelTol', [], ... 'AbsTol', [], ... 'NormControl', 'off', ... 'NonNegative', [], ... 'OutputFcn', [], ... 'OutputSel', [], ... 'OutputSave',[],... 'Refine', 0, ... 'Stats', 'off', ... 'InitialStep', [], ... 'MaxStep', [], ... 'Events', [], ... 'Jacobian', [], ... 'JPattern', [], ... 'Vectorized', 'off', ... 'Mass', [], ... 'MStateDependence', 'weak', ... 'MvPattern', [], ... 'MassSingular', 'maybe', ... 'InitialSlope', [], ... 'MaxOrder', [], ... 'BDF', [], ... 'NewtonTol', [], ... 'MaxNewtonIterations', []); %# Check number and types of all input arguments if (nargin == 0 && nargout == 1) vret = odepkg_structure_check (vtemplate); return; elseif (nargin == 0) help ('odeset'); error ('OdePkg:InvalidArgument', ... 'Number of input arguments must be greater than zero'); elseif (length (varargin) < 2) usage ('odeset ("field1", "value1", ...)'); elseif (ischar (varargin{1}) && mod (length (varargin), 2) == 0) %# Check if there is an odd number of input arguments. If this is %# true then save all the structure names in varg and its values in %# vval and increment vnmb for every option that is found. vnmb = 1; for vcntarg = 1:2:length (varargin) if (ischar (varargin{vcntarg})) varg{vnmb} = varargin{vcntarg}; vval{vnmb} = varargin{vcntarg+1}; vnmb = vnmb + 1; else error ('OdePkg:InvalidArgument', ... 'Input argument number %d is no valid string', vcntarg); end end %# Create and return a new OdePkg structure and fill up all new %# field values that have been found. for vcntarg = 1:(vnmb-1) vtemplate.(varg{vcntarg}) = vval{vcntarg}; end vret = odepkg_structure_check (vtemplate); elseif (isstruct (varargin{1}) && ischar (varargin{2}) && ... mod (length (varargin), 2) == 1) %# Check if there is an even number of input arguments. If this is %# true then the first input argument also must be a valid OdePkg %# structure. Save all the structure names in varg and its values in %# vval and increment the vnmb counter for every option that is %# found. vnmb = 1; for vcntarg = 2:2:length (varargin) if (ischar (varargin{vcntarg})) varg{vnmb} = varargin{vcntarg}; vval{vnmb} = varargin{vcntarg+1}; vnmb = vnmb + 1; else error ('OdePkg:InvalidArgument', ... 'Input argument number %d is no valid string', vcntarg); end end %# Use the old OdePkg structure and fill up all new field values %# that have been found. vret = odepkg_structure_check (varargin{1}); for vcntarg = 1:(vnmb-1) vret.(varg{vcntarg}) = vval{vcntarg}; end vret = odepkg_structure_check (vret); elseif (isstruct (varargin{1}) && isstruct (varargin{2}) && ... length (varargin) == 2) %# Check if the two input arguments are valid OdePkg structures and %# also check if there does not exist any other input argument. vret = odepkg_structure_check (varargin{1}); vnew = odepkg_structure_check (varargin{2}); vfld = fieldnames (vnew); vlen = length (vfld); for vcntfld = 1:vlen if (~isempty (vnew.(vfld{vcntfld}))) vret.(vfld{vcntfld}) = vnew.(vfld{vcntfld}); end end vret = odepkg_structure_check (vret); else error ('OdePkg:InvalidArgument', ... 'Check types and number of all input arguments'); end end %# All tests that are needed to check if a correct resp. valid option %# has been set are implemented in odepkg_structure_check.m. %!test odeoptA = odeset (); %!test odeoptB = odeset ('AbsTol', 1e-2, 'RelTol', 1e-1); %! if (odeoptB.AbsTol ~= 1e-2), error; end %! if (odeoptB.RelTol ~= 1e-1), error; end %!test odeoptB = odeset ('AbsTol', 1e-2, 'RelTol', 1e-1); %! odeoptC = odeset (odeoptB, 'NormControl', 'on'); %!test odeoptB = odeset ('AbsTol', 1e-2, 'RelTol', 1e-1); %! odeoptC = odeset (odeoptB, 'NormControl', 'on'); %! odeoptD = odeset (odeoptC, odeoptB); %!demo %! # A new OdePkg options structure with default values is created. %! %! odeoptA = odeset (); %! %!demo %! # A new OdePkg options structure with manually set options %! # "AbsTol" and "RelTol" is created. %! %! odeoptB = odeset ('AbsTol', 1e-2, 'RelTol', 1e-1); %! %!demo %! # A new OdePkg options structure from odeoptB is created with %! # a modified value for option "NormControl". %! %! odeoptB = odeset ('AbsTol', 1e-2, 'RelTol', 1e-1); %! odeoptC = odeset (odeoptB, 'NormControl', 'on'); %# Local Variables: *** %# mode: octave *** %# End: *** odepkg/Makefile0000644000176000010400000000116711003051261014640 0ustar marcoAdministrators# Filename: Makefile # Description: Makefile for OdePkg # ChangeLog: 20070222, this Makefile was originally be created # from the Makefile of the comm package. Modifications have # been done to create OdePkg. sinclude ../../Makeconf PKG_FILES = COPYING DESCRIPTION INDEX $(wildcard src/*) $(wildcard inst/*) \ doc/odepkg.pdf doc/Makefile $(wildcard doc/*.texi) SUBDIRS = doc/ .PHONY : $(SUBDIRS) pre-pkg:: @for _dir in $(SUBDIRS); do \ $(MAKE) -C $$_dir all; \ done clean : @for _dir in $(SUBDIRS); do \ $(MAKE) -C $$_dir $(MAKECMDGOALS); \ done $(RM) *~ octave-core realclean : clean distclean : clean odepkg/NEWS0000644000176000010400000000043712111613217013704 0ustar marcoAdministratorsSummary of important user-visible changes for odepkg 0.8.4: ------------------------------------------------------------------- ** Added new function ode23s. ** Makefile fixed to work with non-standard linker options e.g on Apple. ** Package is no longer automatically loaded. odepkg/src/0000755000176000010400000000000012111635066013776 5ustar marcoAdministratorsodepkg/src/autogen.sh0000755000176000010400000000132210747712404016002 0ustar marcoAdministrators#! /bin/sh ## Generate ./configure rm -f configure.in echo "dnl --- DO NOT EDIT --- Automatically generated by autogen.sh" > configure.in cat configure.base >> configure.in cat <> configure.in AC_OUTPUT(\$CONFIGURE_OUTPUTS) dnl XXX FIXME XXX chmod is not in autoconf's list of portable functions echo " " echo " \"\\\$prefix\" is \$prefix" echo " \"\\\$exec_prefix\" is \$exec_prefix" AC_MSG_RESULT([\$STATUS_MSG find . -name NOINSTALL -print # shows which toolboxes won't be installed ]) EOF autoconf configure.in > configure.tmp if [ diff configure.tmp configure > /dev/null 2>&1 ]; then rm -f configure.tmp; else mv -f configure.tmp configure chmod 0755 configure fi rm -f configure.in odepkg/src/cash.diff0000644000176000010400000037331510744424256015571 0ustar marcoAdministratorsdiff -u -u cash.orig/mebdfdae.f cash/mebdfdae.f --- cash.orig/mebdfdae.f 2007-12-15 21:33:33.000000000 +0100 +++ cash/mebdfdae.f 2008-01-19 17:41:05.000000000 +0100 @@ -53,13 +53,13 @@ C C NOVEMBER 6th 1998: FIRST RELEASE C -C OVDRIV +C A_OVDRIV C A PACKAGE FOR THE SOLUTION OF THE INITIAL VALUE PROBLEM C FOR SYSTEMS OF ORDINARY DIFFERENTIAL EQUATIONS C DY/DT = F(Y,T), Y=(Y(1),Y(2),Y(3), . . . ,Y(N)) C AND LINEARLY IMPLICIT DIFFERENTIAL ALGEBRAIC EQUATIONS C M(DY/DT) = F(Y,T) -C SUBROUTINE OVDRIV IS A DRIVER ROUTINE FOR THIS PACKAGE +C SUBROUTINE A_OVDRIV IS A DRIVER ROUTINE FOR THIS PACKAGE C C REFERENCES C @@ -79,8 +79,8 @@ C SPRINGER 1996, page 267. C C ---------------------------------------------------------------- -C OVDRIV IS TO BE CALLED ONCE FOR EACH OUTPUT VALUE OF T, AND -C IN TURN MAKES REPEATED CALLS TO THE CORE INTEGRATOR STIFF. +C A_OVDRIV IS TO BE CALLED ONCE FOR EACH OUTPUT VALUE OF T, AND +C IN TURN MAKES REPEATED CALLS TO THE CORE INTEGRATOR A_STIFF. C C THE INPUT PARAMETERS ARE .. C N = THE NUMBER OF FIRST ORDER DIFFERENTIAL EQUATIONS. @@ -165,7 +165,7 @@ C SHOULD BE NON-NEGATIVE. IF ITOL = 1 THEN SINGLE STEP ERROR C ESTIMATES DIVIDED BY YMAX(I) WILL BE KEPT LESS THAN 1 C IN ROOT-MEAN-SQUARE NORM. THE VECTOR YMAX OF WEIGHTS IS -C COMPUTED IN OVDRIV. INITIALLY YMAX(I) IS SET AS +C COMPUTED IN A_OVDRIV. INITIALLY YMAX(I) IS SET AS C THE MAXIMUM OF 1 AND ABS(Y(I)). THEREAFTER YMAX(I) IS C THE LARGEST VALUE OF ABS(Y(I)) SEEN SO FAR, OR THE C INITIAL VALUE YMAX(I) IF THAT IS LARGER. @@ -251,20 +251,20 @@ C IN ADDITION TO OVDRIVE, THE FOLLOWING ROUTINES ARE PROVIDED C IN THE PACKAGE.. C -C INTERP( - ) INTERPOLATES TO GET THE OUTPUT VALUES +C A_INTERP( - ) INTERPOLATES TO GET THE OUTPUT VALUES C AT T=TOUT FROM THE DATA IN THE Y ARRAY. -C STIFF( - ) IS THE CORE INTEGRATOR ROUTINE. IT PERFORMS A +C A_STIFF( - ) IS THE CORE INTEGRATOR ROUTINE. IT PERFORMS A C SINGLE STEP AND ASSOCIATED ERROR CONTROL. -C COSET( - ) SETS COEFFICIENTS FOR BACKWARD DIFFERENTIATION +C A_COSET( - ) SETS COEFFICIENTS FOR BACKWARD DIFFERENTIATION C SCHEMES FOR USE IN THE CORE INTEGRATOR. -C PSET( - ) COMPUTES AND PROCESSES THE JACOBIAN +C A_PSET( - ) COMPUTES AND PROCESSES THE JACOBIAN C MATRIX J = DF/DY -C DEC( - ) PERFORMS AN LU DECOMPOSITION ON A MATRIX. -C SOL( - ) SOLVES LINEAR SYSTEMS A*X = B AFTER DEC +C A_DEC( - ) PERFORMS AN LU DECOMPOSITION ON A MATRIX. +C A_SOL( - ) SOLVES LINEAR SYSTEMS A*X = B AFTER A_DEC C HAS BEEN CALLED FOR THE MATRIX A -C DGBFA ( - ) FACTORS A DOUBLE PRECISION BAND MATRIX BY +C A_DGBFA ( - ) FACTORS A DOUBLE PRECISION BAND MATRIX BY C ELIMINATION. -C DGBSL ( - ) SOLVES A BANDED LINEAR SYSTEM A*x=b +C A_DGBSL ( - ) SOLVES A BANDED LINEAR SYSTEM A*x=b C C ALSO SUPPLIED ARE THE BLAS ROUTINES C @@ -338,7 +338,7 @@ C >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> C THIS SUBROUTINE IS FOR THE PURPOSE * C OF SPLITTING UP THE WORK ARRAYS WORK AND IWORK * -C FOR USE INSIDE THE INTEGRATOR STIFF * +C FOR USE INSIDE THE INTEGRATOR A_STIFF * C <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C .. SCALAR ARGUMENTS .. @@ -353,7 +353,7 @@ C COMMON BLOCKS C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL OVDRIV,F,PDERV,MAS + EXTERNAL A_OVDRIV,F,PDERV,MAS C .. C .. SAVE STATEMENT .. SAVE I1,I2,I3,I4,I5,I6,I7,I8,I9,I10,I11,I12 @@ -401,7 +401,7 @@ c WORKSPACE HAS TO BE AT LEAST N+14. c - CALL OVDRIV(N,T0,HO,Y0,TOUT,TEND,MF,IDID,LOUT,WORK(3),WORK(I1), + CALL A_OVDRIV(N,T0,HO,Y0,TOUT,TEND,MF,IDID,LOUT,WORK(3),WORK(I1), + WORK(I2),WORK(I3),WORK(I4),WORK(I5),WORK(I6),WORK(I7), + WORK(I8),WORK(I9),WORK(I10),WORK(I11),IWORK(15),MBND,MASBND, + IWORK(1),IWORK(2),IWORK(3),MAXDER,ITOL,RTOL,ATOL,RPAR,IPAR, @@ -431,7 +431,7 @@ + ' WITH N = ',I6) END - SUBROUTINE OVDRIV(N,T0,HO,Y0,TOUT,TEND,MF,IDID,LOUT,Y,YHOLD, + SUBROUTINE A_OVDRIV(N,T0,HO,Y0,TOUT,TEND,MF,IDID,LOUT,Y,YHOLD, + YNHOLD,YMAX,ERRORS,SAVE1,SAVE2,SCALE,ARH,PW,PWCOPY, + AM,IPIV,MBND,MASBND,NIND1,NIND2,NIND3,MAXDER,ITOL, + RTOL,ATOL,RPAR,IPAR,F,PDERV,MAS,NQUSED,NSTEP,NFAIL, @@ -457,7 +457,7 @@ INTEGER I,KGO,NHCUT C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL INTERP,STIFF,F,PDERV,MAS + EXTERNAL A_INTERP,A_STIFF,F,PDERV,MAS C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DABS,DMAX1 @@ -475,7 +475,7 @@ HMAX = DABS(TEND-T0)*10.0D+0 IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT THE OUTPUT POINT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IDID = KFLAG T0 = TOUT HO = H @@ -493,7 +493,7 @@ IF (((T-TOUT)*H.GE.0.0D+0) .OR. (DABS(T-TOUT).LE. + 100.0D+0*UROUND*HMAX)) THEN C HAVE OVERSHOT THE OUTPUT POINT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) T0 = TOUT HO = H IDID = KFLAG @@ -520,7 +520,7 @@ IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT TOUT WRITE (LOUT,9080) T,TOUT,H - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) HO = H T0 = TOUT IDID = -5 @@ -534,7 +534,7 @@ T0 = T IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT,SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IDID = KFLAG T0 = TOUT HO = H @@ -667,7 +667,7 @@ 20 IF ((T+H).EQ.T) THEN WRITE (LOUT,9000) END IF - CALL STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND,MASBND, + CALL A_STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND,MASBND, + NIND1,NIND2,NIND3,T,TOUT,TEND,Y,N, + YMAX,ERRORS,SAVE1,SAVE2,SCALE,PW,PWCOPY,AM,YHOLD, + YNHOLD,ARH,IPIV,LOUT,MAXDER,ITOL,RTOL,ATOL,RPAR,IPAR,F, @@ -679,7 +679,7 @@ ENDIF KGO = 1 - KFLAG IF (KGO.EQ.1) THEN -C NORMAL RETURN FROM STIFF +C NORMAL RETURN FROM A_STIFF GO TO 30 ELSE IF (KGO.EQ.2) THEN @@ -756,7 +756,7 @@ IF (((T-TOUT)*H.GE.0.0D+0) .OR. (DABS(T-TOUT).LE. + 100.0D+0*UROUND*HMAX)) THEN C HAVE OVERSHOT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) T0 = TOUT HO = H IDID = KFLAG @@ -773,7 +773,7 @@ ELSE IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IDID = KFLAG HO = H T0 = TOUT @@ -812,14 +812,14 @@ ELSE C HAVE PASSED TOUT SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) T0 = TOUT IDID = KFLAG END IF HO = H IF(KFLAG.NE.0) IDID = KFLAG RETURN -C -------------------------- END OF SUBROUTINE OVDRIV ----------------- +C -------------------------- END OF SUBROUTINE A_OVDRIV ----------------- 9000 FORMAT (' WARNING.. T + H = T ON NEXT STEP.') 9010 FORMAT (/,/,' KFLAG = -2 FROM INTEGRATOR AT T = ',E16.8,' H =', + E16.8,/, @@ -853,7 +853,7 @@ END - SUBROUTINE INTERP(N,JSTART,H,T,Y,TOUT,Y0) + SUBROUTINE A_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C .. SCALAR ARGUMENTS .. @@ -880,14 +880,14 @@ 20 CONTINUE 30 CONTINUE RETURN -C -------------- END OF SUBROUTINE INTERP --------------------------- +C -------------- END OF SUBROUTINE A_INTERP --------------------------- END - SUBROUTINE COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + SUBROUTINE A_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C -------------------------------------------------------------------- -C COSET IS CALLED BY THE INTEGRATOR AND SETS THE COEFFICIENTS USED +C A_COSET IS CALLED BY THE INTEGRATOR AND SETS THE COEFFICIENTS USED C BY THE CONVENTIONAL BACKWARD DIFFERENTIATION SCHEME AND THE C MODIFIED EXTENDED BACKWARD DIFFERENTIATION SCHEME. THE VECTOR C EL OF LENGTH NQ+1 DETERMINES THE BASIC BDF METHOD WHILE THE VECTOR @@ -1017,10 +1017,10 @@ TQ(4) = 0.5D+0*TQ(2)/DBLE(FLOAT(NQ)) IF(NQ.NE.1) TQ(5)=PERTST(NQ-1,1) RETURN -C --------------------- END OF SUBROUTINE COSET --------------------- +C --------------------- END OF SUBROUTINE A_COSET --------------------- END - SUBROUTINE PSET(Y,N,H,T,UROUND,EPSJAC,CON,MITER,MBND, + SUBROUTINE A_PSET(Y,N,H,T,UROUND,EPSJAC,CON,MITER,MBND, + MASBND,NIND1,NIND2,NIND3,IER,F,PDERV,MAS, + NRENEW,YMAX,SAVE1,SAVE2,PW,PWCOPY,AM,WRKSPC,IPIV, + ITOL,RTOL,ATOL,NPSET,NJE,NFE,NDEC,IPAR,RPAR,IERR) @@ -1029,7 +1029,7 @@ IMPLICIT DOUBLE PRECISION(A-H,O-Z) C ------------------------------------------------------------------- -C PSET IS CALLED BY STIFF TO COMPUTE AND PROCESS THE MATRIX +C A_PSET IS CALLED BY A_STIFF TO COMPUTE AND PROCESS THE MATRIX C M/(H*EL(1)) - J WHERE J IS AN APPROXIMATION TO THE RELEVANT JACOBIAN C AND M IS THE MASS MATRIX. THIS MATRIX IS THEN SUBJECTED TO LU C DECOMPOSITION IN PREPARATION FOR LATER SOLUTION OF LINEAR SYSTEMS @@ -1037,7 +1037,7 @@ C MATRIX J IS FOUND BY THE USER-SUPPLIED ROUTINE PDERV IF MITER=1 C OR 3 OR BY FINITE DIFFERENCING IF MITER = 2 OR 4. C IN ADDITION TO VARIABLES DESCRIBED PREVIOUSLY, COMMUNICATION WITH -C PSET USES THE FOLLOWING .. +C A_PSET USES THE FOLLOWING .. C EPSJAC = DSQRT(UROUND), USED IN NUMERICAL JACOBIAN INCREMENTS. C ******************************************************************* C THE ARGUMENT NRENEW IS USED TO SIGNAL WHETHER OR NOT @@ -1060,7 +1060,7 @@ INTEGER I,J,J1,JJKK,FOUR,FIVE C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL DEC,F,PDERV,DGBFA,MAS + EXTERNAL A_DEC,F,PDERV,A_DGBFA,MAS C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DABS,DMAX1,DSQRT @@ -1267,7 +1267,7 @@ II = II + MBND(4) 75 CONTINUE ENDIF - CALL DGBFA(PW,MBND(4),N,ML,MU,IPIV,IER) + CALL A_DGBFA(PW,MBND(4),N,ML,MU,IPIV,IER) NDEC = NDEC + 1 ELSE IF(MASBND(1).EQ.0) THEN @@ -1278,13 +1278,13 @@ J = J + NP1 80 CONTINUE ENDIF - CALL DEC(N,N,PW,IPIV,IER) + CALL A_DEC(N,N,PW,IPIV,IER) NDEC = NDEC + 1 ENDIF RETURN -C ---------------------- END OF SUBROUTINE PSET --------------------- +C ---------------------- END OF SUBROUTINE A_PSET --------------------- END - SUBROUTINE DEC(N,NDIM,A,IP,IER) + SUBROUTINE A_DEC(N,NDIM,A,IP,IER) IMPLICIT DOUBLE PRECISION(A-H,O-Z) @@ -1301,9 +1301,9 @@ C IP(N) = (-1)**(NUMBER OF INTERCHANGES) OR 0. C IER = 0 IF MATRIX IS NON-SINGULAR, OR K IF FOUND TO BE SINGULAR C AT STAGE K. -C USE SOL TO OBTAIN SOLUTION OF LINEAR SYSTEM. +C USE A_SOL TO OBTAIN SOLUTION OF LINEAR SYSTEM. C DETERM(A) = IP(N)*A(1,1)*A(2,2)* . . . *A(N,N). -C IF IP(N) = 0, A IS SINGULAR, SOL WILL DIVIDE BY ZERO. +C IF IP(N) = 0, A IS SINGULAR, A_SOL WILL DIVIDE BY ZERO. C C REFERENCE. C C.B. MOLER, ALGORITHM 423, LINEAR EQUATION SOLVER, C.A.C.M @@ -1362,9 +1362,9 @@ 80 IER = K IP(N) = 0 RETURN -C --------------------- END OF SUBROUTINE DEC ---------------------- +C --------------------- END OF SUBROUTINE A_DEC ---------------------- END - SUBROUTINE SOL(N,NDIM,A,B,IP) + SUBROUTINE A_SOL(N,NDIM,A,B,IP) IMPLICIT DOUBLE PRECISION(A-H,O-Z) @@ -1386,10 +1386,10 @@ C INPUT .. C N = ORDER OF MATRIX. C NDIM = DECLARED DIMENSION OF MATRIX A. -C A = TRIANGULARISED MATRIX OBTAINED FROM DEC. +C A = TRIANGULARISED MATRIX OBTAINED FROM A_DEC. C B = RIGHT HAND SIDE VECTOR. -C IP = PIVOT VECTOR OBTAINED FROM DEC. -C DO NOT USE IF DEC HAS SET IER .NE. 0 +C IP = PIVOT VECTOR OBTAINED FROM A_DEC. +C DO NOT USE IF A_DEC HAS SET IER .NE. 0 C OUTPUT.. C B = SOLUTION VECTOR, X. C ------------------------------------------------------------------ @@ -1416,15 +1416,15 @@ 40 CONTINUE 50 B(1) = B(1)/A(1,1) RETURN -C ------------------------- END OF SUBROUTINE SOL ------------------ +C ------------------------- END OF SUBROUTINE A_SOL ------------------ END - subroutine dgbfa(abd,lda,n,ml,mu,ipvt,info) + subroutine a_dgbfa(abd,lda,n,ml,mu,ipvt,info) integer lda,n,ml,mu,ipvt(1),info double precision abd(lda,1) c -c dgbfa factors a double precision band matrix by elimination. +c a_dgbfa factors a double precision band matrix by elimination. c -c dgbfa is usually called by dgbco, but it can be called +c a_dgbfa is usually called by dgbco, but it can be called c directly with a saving in time if rcond is not needed. c c on entry @@ -1466,7 +1466,7 @@ c = 0 normal value. c = k if u(k,k) .eq. 0.0 . this is not an error c condition for this subroutine, but it does -c indicate that dgbsl will divide by zero if +c indicate that a_dgbsl will divide by zero if c called. use rcond in dgbco for a reliable c indication of singularity. c @@ -1593,151 +1593,18 @@ return end c - subroutine daxpy(n,da,dx,incx,dy,incy) -c -c constant times a vector plus a vector. -c uses unrolled loops for increments equal to one. -c jack dongarra, linpack, 3/11/78. -c - double precision dx(1),dy(1),da - integer i,incx,incy,ix,iy,m,mp1,n -c - if(n.le.0)return - if (da .eq. 0.0d0) return - if(incx.eq.1.and.incy.eq.1)go to 20 -c -c code for unequal increments or equal increments -c not equal to 1 -c - ix = 1 - iy = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - if(incy.lt.0)iy = (-n+1)*incy + 1 - do 10 i = 1,n - dy(iy) = dy(iy) + da*dx(ix) - ix = ix + incx - iy = iy + incy - 10 continue - return -c -c code for both increments equal to 1 -c -c -c clean-up loop -c - 20 m = mod(n,4) - if( m .eq. 0 ) go to 40 - do 30 i = 1,m - dy(i) = dy(i) + da*dx(i) - 30 continue - if( n .lt. 4 ) return - 40 mp1 = m + 1 - do 50 i = mp1,n,4 - dy(i) = dy(i) + da*dx(i) - dy(i + 1) = dy(i + 1) + da*dx(i + 1) - dy(i + 2) = dy(i + 2) + da*dx(i + 2) - dy(i + 3) = dy(i + 3) + da*dx(i + 3) - 50 continue - return - end -c - subroutine dscal(n,da,dx,incx) -c -c scales a vector by a constant. -c uses unrolled loops for increment equal to one. -c jack dongarra, linpack, 3/11/78. -c modified to correct problem with negative increment, 8/21/90. -c - double precision da,dx(1) - integer i,incx,ix,m,mp1,n -c - if(n.le.0)return - if(incx.eq.1)go to 20 -c -c code for increment not equal to 1 -c - ix = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - do 10 i = 1,n - dx(ix) = da*dx(ix) - ix = ix + incx - 10 continue - return -c -c code for increment equal to 1 -c -c -c clean-up loop -c - 20 m = mod(n,5) - if( m .eq. 0 ) go to 40 - do 30 i = 1,m - dx(i) = da*dx(i) - 30 continue - if( n .lt. 5 ) return - 40 mp1 = m + 1 - do 50 i = mp1,n,5 - dx(i) = da*dx(i) - dx(i + 1) = da*dx(i + 1) - dx(i + 2) = da*dx(i + 2) - dx(i + 3) = da*dx(i + 3) - dx(i + 4) = da*dx(i + 4) - 50 continue - return - end -c - integer function idamax(n,dx,incx) -c -c finds the index of element having max. absolute value. -c jack dongarra, linpack, 3/11/78. -c modified to correct problem with negative increment, 8/21/90. -c - double precision dx(1),dmax - integer i,incx,ix,n -c - idamax = 0 - if( n .lt. 1 ) return - idamax = 1 - if(n.eq.1)return - if(incx.eq.1)go to 20 -c -c code for increment not equal to 1 -c - ix = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - dmax = dabs(dx(ix)) - ix = ix + incx - do 10 i = 2,n - if(dabs(dx(ix)).le.dmax) go to 5 - idamax = i - dmax = dabs(dx(ix)) - 5 ix = ix + incx - 10 continue - return -c -c code for increment equal to 1 -c - 20 dmax = dabs(dx(1)) - do 30 i = 2,n - if(dabs(dx(i)).le.dmax) go to 30 - idamax = i - dmax = dabs(dx(i)) - 30 continue - return - end - - subroutine dgbsl(abd,lda,n,ml,mu,ipvt,b,job) + subroutine a_dgbsl(abd,lda,n,ml,mu,ipvt,b,job) integer lda,n,ml,mu,ipvt(*),job double precision abd(lda,*),b(*) c -c dgbsl solves the double precision band system +c a_dgbsl solves the double precision band system c a * x = b or trans(a) * x = b -c using the factors computed by dgbco or dgbfa. +c using the factors computed by dgbco or a_dgbfa. c c on entry c c abd double precision(lda, n) -c the output from dgbco or dgbfa. +c the output from dgbco or a_dgbfa. c c lda integer c the leading dimension of the array abd . @@ -1752,7 +1619,7 @@ c number of diagonals above the main diagonal. c c ipvt integer(n) -c the pivot vector from dgbco or dgbfa. +c the pivot vector from dgbco or a_dgbfa. c c b double precision(n) c the right hand side vector. @@ -1773,14 +1640,14 @@ c but it is often caused by improper arguments or improper c setting of lda . it will not occur if the subroutines are c called correctly and if dgbco has set rcond .gt. 0.0 -c or dgbfa has set info .eq. 0 . +c or a_dgbfa has set info .eq. 0 . c c to compute inverse(a) * c where c is a matrix c with p columns c call dgbco(abd,lda,n,ml,mu,ipvt,rcond,z) c if (rcond is too small) go to ... c do 10 j = 1, p -c call dgbsl(abd,lda,n,ml,mu,ipvt,c(1,j),0) +c call a_dgbsl(abd,lda,n,ml,mu,ipvt,c(1,j),0) c 10 continue c c linpack. this version dated 08/14/78 . @@ -1862,62 +1729,13 @@ return end c - double precision function ddot(n,dx,incx,dy,incy) -c -c forms the dot product of two vectors. -c uses unrolled loops for increments equal to one. -c jack dongarra, linpack, 3/11/78. -c - double precision dx(1),dy(1),dtemp - integer i,incx,incy,ix,iy,m,mp1,n -c - ddot = 0.0d0 - dtemp = 0.0d0 - if(n.le.0)return - if(incx.eq.1.and.incy.eq.1)go to 20 -c -c code for unequal increments or equal increments -c not equal to 1 -c - ix = 1 - iy = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - if(incy.lt.0)iy = (-n+1)*incy + 1 - do 10 i = 1,n - dtemp = dtemp + dx(ix)*dy(iy) - ix = ix + incx - iy = iy + incy - 10 continue - ddot = dtemp - return -c -c code for both increments equal to 1 -c -c -c clean-up loop -c - 20 m = mod(n,5) - if( m .eq. 0 ) go to 40 - do 30 i = 1,m - dtemp = dtemp + dx(i)*dy(i) - 30 continue - if( n .lt. 5 ) go to 60 - 40 mp1 = m + 1 - do 50 i = mp1,n,5 - dtemp = dtemp + dx(i)*dy(i) + dx(i + 1)*dy(i + 1) + - * dx(i + 2)*dy(i + 2) + dx(i + 3)*dy(i + 3) + dx(i + 4)*dy(i + 4) - 50 continue - 60 ddot = dtemp - return - end - - SUBROUTINE ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + SUBROUTINE A_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C *************************************************** C C THIS ROUTINE CALCULATES ERRORS USED IN TESTS -C IN STIFF . +C IN A_STIFF . C C *************************************************** C .. SCALAR ARGUMENTS .. @@ -1950,7 +1768,7 @@ C ** ERROR ASSOCIATED WITH METHOD OF ORDER TWO LOWER. RETURN END - SUBROUTINE PRDICT(T,H,Y,L,N,YPRIME,NFE,IPAR,RPAR,F,IERR) + SUBROUTINE A_PRDICT(T,H,Y,L,N,YPRIME,NFE,IPAR,RPAR,F,IERR) @@ -1987,10 +1805,10 @@ RETURN END - SUBROUTINE ITRAT2(QQQ,Y,N,T,HBETA,ERRBND,ARH,CRATE,TCRATE,M,WORKED - + ,YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND,AM,MASBND,NIND1, - + NIND2,NIND3,IPIV,LMB,ITOL,RTOL,ATOL,IPAR,RPAR,HUSED,NBSOL, - + NFE,NQUSED,F,IERR) + SUBROUTINE A_ITRAT2(QQQ,Y,N,T,HBETA,ERRBND,ARH,CRATE,TCRATE,M, + + WORKED,YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND,AM,MASBND, + + NIND1,NIND2,NIND3,IPIV,LMB,ITOL,RTOL,ATOL,IPAR,RPAR,HUSED, + + NBSOL,NFE,NQUSED,F,IERR) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C .. SCALAR ARGUMENTS .. @@ -2006,7 +1824,7 @@ INTEGER I C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL F,SOL,DGBSL + EXTERNAL F,A_SOL,A_DGBSL C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DMAX1,DMIN1 @@ -2077,10 +1895,10 @@ 8812 CONTINUE ENDIF IF(MF.GE.23) THEN - CALL DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) + CALL A_DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) NBSOL = NBSOL + 1 ELSE - CALL SOL(N,N,PW,SAVE1,IPIV) + CALL A_SOL(N,N,PW,SAVE1,IPIV) NBSOL = NBSOL + 1 ENDIF D = ZERO @@ -2131,10 +1949,10 @@ C IF WE ARE HERE THEN PARTIALS ARE O.K. C IF( MF.GE. 23) THEN - CALL DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) + CALL A_DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) NBSOL=NBSOL + 1 ELSE - CALL SOL(N,N,PW,SAVE1,IPIV) + CALL A_SOL(N,N,PW,SAVE1,IPIV) NBSOL = NBSOL + 1 ENDIF C @@ -2180,7 +1998,7 @@ END - SUBROUTINE STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND, + SUBROUTINE A_STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND, + MASBND,NIND1,NIND2,NIND3,T,TOUT,TEND,Y,N, + YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,PWCOPY,AM,YHOLD, + YNHOLD,ARH,IPIV,LOUT,MAXDER,ITOL,RTOL,ATOL,RPAR,IPAR,F, @@ -2191,13 +2009,13 @@ IMPLICIT DOUBLE PRECISION(A-H,O-Z) C ------------------------------------------------------------------ -C THE SUBROUTINE STIFF PERFORMS ONE STEP OF THE INTEGRATION OF AN +C THE SUBROUTINE A_STIFF PERFORMS ONE STEP OF THE INTEGRATION OF AN C INITIAL VALUE PROBLEM FOR A SYSTEM OF ORDINARY DIFFERENTIAL C EQUATIONS OR LINEARLY IMPLICIT DIFFERENTIAL ALGEBRAIC EQUATIONS. -C COMMUNICATION WITH STIFF IS DONE WITH THE FOLLOWING VARIABLES.. +C COMMUNICATION WITH A_STIFF IS DONE WITH THE FOLLOWING VARIABLES.. C Y AN N BY LMAX+3 ARRAY CONTAINING THE DEPENDENT VARIABLES C AND THEIR BACKWARD DIFFERENCES. MAXDER (=LMAX-1) IS THE -C MAXIMUM ORDER AVAILABLE. SEE SUBROUTINE COSET. +C MAXIMUM ORDER AVAILABLE. SEE SUBROUTINE A_COSET. C Y(I,J+1) CONTAINS THE JTH BACKWARD DIFFERENCE OF Y(I) C T THE INDEPENDENT VARIABLE. T IS UPDATED ON EACH STEP TAKEN. C H THE STEPSIZE TO BE ATTEMPTED ON THE NEXT STEP. @@ -2207,7 +2025,7 @@ C HMIN THE MINIMUM AND MAXIMUM ABSOLUTE VALUE OF THE STEPSIZE C HMAX TO BE USED FOR THE STEP. THESE MAY BE CHANGED AT ANY C TIME BUT WILL NOT TAKE EFFECT UNTIL THE NEXT H CHANGE. -C RTOL,ATOL THE ERROR BOUNDS. SEE DESCRIPTION IN OVDRIV. +C RTOL,ATOL THE ERROR BOUNDS. SEE DESCRIPTION IN A_OVDRIV. C N THE NUMBER OF FIRST ORDER DIFFERENTIAL EQUATIONS. C MF THE METHOD FLAG. MUST BE SET TO 21,22,23 OR 24 AT PRESENT C KFLAG A COMPLETION FLAG WITH THE FOLLOWING MEANINGS.. @@ -2242,7 +2060,7 @@ C MATRIX WAS FORMED BY A NEW J. C AVOLDJ STORES VALUE FOR AVERAGE CRATE WHEN ITERATION C MATRIX WAS FORMED BY AN OLD J. -C NRENEW FLAG THAT IS USED IN COMMUNICATION WITH SUBROUTINE PSET. +C NRENEW FLAG THAT IS USED IN COMMUNICATION WITH SUBROUTINE A_PSET. C IF NRENEW > 0 THEN FORM A NEW JACOBIAN BEFORE C COMPUTING THE COEFFICIENT MATRIX FOR C THE NEWTON-RAPHSON ITERATION @@ -2271,8 +2089,8 @@ DIMENSION EL(10),ELST(10),TQ(5) C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL COSET,CPYARY,ERRORS,F,HCHOSE,ITRAT2, - + PRDICT,PSET,RSCALE,SOL,DGBSL,PDERV,MAS + EXTERNAL A_COSET,A_CPYARY,A_ERRORS,F,A_HCHOSE,A_ITRAT2, + + A_PRDICT,A_PSET,A_RSCALE,A_SOL,A_DGBSL,PDERV,MAS C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DABS,DMAX1,DMIN1 @@ -2378,7 +2196,7 @@ C BE RE-SCALED. IF H IS CHANGED, IDOUB IS SET TO L+1 TO PREVENT C FURTHER CHANGES IN H FOR THAT MANY STEPS. C ----------------------------------------------------------------- - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL A_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) LMAX = MAXDER + 1 RC = RC*EL(1)/OLDLO OLDLO = EL(1) @@ -2389,20 +2207,20 @@ C NRENEW AND NEWPAR ARE TO INSTRUCT ROUTINE THAT C WE WISH A NEW J TO BE CALCULATED FOR THIS STEP. C ***************************************************** - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL A_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) DO 20 I = 1,N ARH(I) = EL(2)*Y(I,1) 20 CONTINUE - CALL CPYARY(N*L,Y,YHOLD) + CALL A_CPYARY(N*L,Y,YHOLD) QI = H*EL(1) QQ = ONE/QI - CALL PRDICT(T,H,Y,L,N,SAVE2,NFE,IPAR,RPAR,F,IERR) + CALL A_PRDICT(T,H,Y,L,N,SAVE2,NFE,IPAR,RPAR,F,IERR) IF(IERR.NE.0) GOTO 8000 GO TO 110 C >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> C DIFFERENT PARAMETERS ON THIS CALL < C <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - 30 CALL CPYARY(N*L,YHOLD,Y) + 30 CALL A_CPYARY(N*L,YHOLD,Y) IF (MF.NE.MFOLD) THEN METH = MF/10 MITER = MF - 10*METH @@ -2445,7 +2263,7 @@ C ********************************************* 40 RH = DMAX1(RH,HMIN/DABS(H)) 50 RH = DMIN1(RH,HMAX/DABS(H),RMAX) - CALL RSCALE(N,L,RH,Y) + CALL A_RSCALE(N,L,RH,Y) RMAX = 10.0D+0 JCHANG = 1 H = H*RH @@ -2462,7 +2280,7 @@ END IF IDOUB = L + 1 - CALL CPYARY(N*L,Y,YHOLD) + CALL A_CPYARY(N*L,Y,YHOLD) 60 IF (DABS(RC-ONE).GT.UPBND) IWEVAL = MITER HUSED = H @@ -2487,7 +2305,7 @@ IF (JCHANG.EQ.1) THEN C IF WE HAVE CHANGED STEPSIZE THEN PREDICT A VALUE FOR Y(T+H) C AND EVALUATE THE DERIVATIVE THERE (STORED IN SAVE2()) - CALL PRDICT(T,H,Y,L,N,SAVE2,NFE,IPAR,RPAR,F,IERR) + CALL A_PRDICT(T,H,Y,L,N,SAVE2,NFE,IPAR,RPAR,F,IERR) IF(IERR.NE.0) GOTO 8000 ELSE @@ -2507,7 +2325,7 @@ C ------------------------------------------------------------------- C IF INDICATED, THE MATRIX P = I/(H*EL(2)) - J IS RE-EVALUATED BEFORE C STARTING THE CORRECTOR ITERATION. IWEVAL IS SET = 0 TO INDICATE -C THAT THIS HAS BEEN DONE. P IS COMPUTED AND PROCESSED IN PSET. +C THAT THIS HAS BEEN DONE. P IS COMPUTED AND PROCESSED IN A_PSET. C THE PROCESSED MATRIX IS STORED IN PW C ------------------------------------------------------------------- IWEVAL = 0 @@ -2573,13 +2391,13 @@ JSNOLD = 0 MQ1TMP = MEQC1 MQ2TMP = MEQC2 - CALL PSET(Y,N,H,T,UROUND,EPSJAC,QI,MITER,MBND,MASBND, + CALL A_PSET(Y,N,H,T,UROUND,EPSJAC,QI,MITER,MBND,MASBND, + NIND1,NIND2,NIND3,IER,F,PDERV,MAS,NRENEW,YMAX,SAVE1,SAVE2, + PW,PWCOPY,AM,ERROR,IPIV,ITOL,RTOL,ATOL,NPSET,NJE,NFE,NDEC,IPAR + ,RPAR,IERR) IF(IERR.NE.0) GOTO 8000 QQQ=QI -C NOTE THAT ERROR() IS JUST BEING USED AS A WORKSPACE BY PSET +C NOTE THAT ERROR() IS JUST BEING USED AS A WORKSPACE BY A_PSET IF (IER.NE.0) THEN C IF IER>0 THEN WE HAVE HAD A SINGULARITY IN THE ITERATION MATRIX IJUS=1 @@ -2603,7 +2421,7 @@ C LOOP. THE UPDATED Y VECTOR IS STORED TEMPORARILY IN SAVE1. C ********************************************************************** IF (.NOT.SAMPLE) THEN - CALL ITRAT2(QQQ,Y,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1,WORKED,YMAX, + CALL A_ITRAT2(QQQ,Y,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1,WORKED,YMAX, + ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND,AM,MASBND, + NIND1,NIND2,NIND3,IPIV,1,ITOL,RTOL,ATOL,IPAR,RPAR,HUSED,NBSOL, + NFE,NQUSED,F,IERR) @@ -2611,7 +2429,7 @@ ITST = 2 ELSE - CALL ITRAT2(QQQ,Y,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1,WORKED,YMAX, + CALL A_ITRAT2(QQQ,Y,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1,WORKED,YMAX, + ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND,AM,MASBND, +NIND1,NIND2,NIND3,IPIV,0,ITOL,RTOL,ATOL,IPAR,RPAR,HUSED,NBSOL, + NFE,NQUSED,F,IERR) @@ -2752,7 +2570,7 @@ ARH(I) = ARH(I) + EL(JP1)*Y(I,J1) 200 CONTINUE 210 CONTINUE - CALL PRDICT(T,H,Y,L,N,SAVE2,NFE,IPAR,RPAR,F,IERR) + CALL A_PRDICT(T,H,Y,L,N,SAVE2,NFE,IPAR,RPAR,F,IERR) IF(IERR.NE.0) GOTO 8000 DO 220 I = 1,N SAVE1(I) = Y(I,1) @@ -2763,7 +2581,7 @@ C FOR NOW WILL ASSUME THAT WE DO NOT WISH TO SAMPLE C AT THE N+2 STEP POINT C - CALL ITRAT2(QQQ,Y,N,T,QI,BND,ARH,CRATE2,TCRAT2,M2,WORKED,YMAX, + CALL A_ITRAT2(QQQ,Y,N,T,QI,BND,ARH,CRATE2,TCRAT2,M2,WORKED,YMAX, + ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND,AM,MASBND, +NIND1,NIND2,NIND3,IPIV,1,ITOL,RTOL,ATOL,IPAR,RPAR,HUSED,NBSOL, + NFE,NQUSED,F,IERR) @@ -2872,10 +2690,10 @@ 3111 CONTINUE ENDIF IF (MF.GE. 23) THEN - CALL DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) + CALL A_DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) NBSOL=NBSOL+1 ELSE - CALL SOL(N,N,PW,SAVE1,IPIV) + CALL A_SOL(N,N,PW,SAVE1,IPIV) NBSOL = NBSOL + 1 ENDIF DO 321 I=1,N @@ -2971,7 +2789,7 @@ IF(NQ.GT.1) FFAIL = 0.5D+0/DBLE(FLOAT(NQ)) IF(NQ.GT.2) FRFAIL = 0.5D+0/DBLE(FLOAT(NQ-1)) EFAIL = 0.5D+0/DBLE(FLOAT(L)) - CALL CPYARY(N*L,YHOLD,Y) + CALL A_CPYARY(N*L,YHOLD,Y) RMAX = 2.0D+0 IF (DABS(H).LE.HMIN*1.00001D+0) THEN C @@ -3000,10 +2818,10 @@ NQ=NEWQ RH=ONE/(PLFAIL*DBLE(FLOAT(-KFAIL))) L=NQ+1 - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL A_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) RC=RC*EL(1)/OLDLO OLDLO=EL(1) - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL A_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) ELSE NEWQ = NQ RH = ONE/ (PRFAIL*DBLE(FLOAT(-KFAIL))) @@ -3029,7 +2847,7 @@ C ********************************* JCHANG = 1 RH = DMAX1(HMIN/DABS(H),0.1D+0) - CALL HCHOSE(RH,H,OVRIDE) + CALL A_HCHOSE(RH,H,OVRIDE) H = H*RH CALL F(N,T,YHOLD,SAVE1,IPAR,RPAR,IERR) IF(IERR.NE.0) GOTO 8000 @@ -3048,11 +2866,11 @@ NQ = 1 L = 2 C RESET ORDER, RECALCULATE ERROR BOUNDS - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL A_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) LMAX = MAXDER + 1 RC = RC*EL(1)/OLDLO OLDLO = EL(1) - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL A_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) C NOW JUMP TO NORMAL CONTINUATION POINT GO TO 60 C ********************************************************************** @@ -3216,7 +3034,7 @@ GOTO 440 ENDIF RH = DMIN1(RH,RMAX) - CALL HCHOSE(RH,H,OVRIDE) + CALL A_HCHOSE(RH,H,OVRIDE) IF ((JSINUP.LE.20).AND.(KFLAG.EQ.0).AND.(RH.LT.1.1D+0)) THEN C WE HAVE RUN INTO PROBLEMS IDOUB = 10 @@ -3244,17 +3062,17 @@ NQ = NEWQ L = NQ + 1 C RESET ORDER,RECALCULATE ERROR BOUNDS - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL A_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) LMAX = MAXDER + 1 RC = RC*EL(1)/OLDLO OLDLO = EL(1) - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL A_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) END IF RH = DMAX1(RH,HMIN/DABS(H)) RH = DMIN1(RH,HMAX/DABS(H),RMAX) - CALL RSCALE(N,L,RH,Y) + CALL A_RSCALE(N,L,RH,Y) RMAX = 10.0D+0 JCHANG = 1 H = H*RH @@ -3271,7 +3089,7 @@ C INFORMATION NECESSARY TO PERFORM AN INTERPOLATION TO FIND THE C SOLUTION AT THE SPECIFIED OUTPUT POINT IF APPROPRIATE. C ---------------------------------------------------------------------- - CALL CPYARY(N*L,Y,YHOLD) + CALL A_CPYARY(N*L,Y,YHOLD) NSTEP = NSTEP + 1 JSINUP = JSINUP + 1 JSNOLD = JSNOLD + 1 @@ -3312,17 +3130,17 @@ C TRY AGAIN WITH UPDATED PARTIALS C 8000 IF(IERR.NE.0) RETURN - IF(IJUS.EQ.0) CALL HCHOSE(RH,H,OVRIDE) + IF(IJUS.EQ.0) CALL A_HCHOSE(RH,H,OVRIDE) IF(.NOT.FINISH) THEN GO TO 40 ELSE RETURN END IF -C ------------------- END OF SUBROUTINE STIFF -------------------------- +C ------------------- END OF SUBROUTINE A_STIFF -------------------------- 9000 FORMAT (1X,' CORRECTOR HAS NOT CONVERGED') END - SUBROUTINE RSCALE(N,L,RH,Y) + SUBROUTINE A_RSCALE(N,L,RH,Y) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C .. SCALAR ARGUMENTS .. @@ -3432,7 +3250,7 @@ RETURN END - SUBROUTINE CPYARY(NELEM,SOURCE,TARGET) + SUBROUTINE A_CPYARY(NELEM,SOURCE,TARGET) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C C COPIES THE ARRAY SOURCE() INTO THE ARRAY TARGET() @@ -3455,7 +3273,7 @@ RETURN END - SUBROUTINE HCHOSE(RH,H,OVRIDE) + SUBROUTINE A_HCHOSE(RH,H,OVRIDE) IMPLICIT DOUBLE PRECISION(A-H,O-Z) COMMON / STPSZE / HSTPSZ(2,14) LOGICAL OVRIDE @@ -3492,947 +3310,3 @@ C ************************************************************ C END - DOUBLE PRECISION FUNCTION DLAMCH( CMACH ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - CHARACTER CMACH -* .. -* -* Purpose -* ======= -* -* DLAMCH determines double precision machine parameters. -* -* Arguments -* ========= -* -* CMACH (input) CHARACTER*1 -* Specifies the value to be returned by DLAMCH: -* = 'E' or 'e', DLAMCH := eps -* = 'S' or 's , DLAMCH := sfmin -* = 'B' or 'b', DLAMCH := base -* = 'P' or 'p', DLAMCH := eps*base -* = 'N' or 'n', DLAMCH := t -* = 'R' or 'r', DLAMCH := rnd -* = 'M' or 'm', DLAMCH := emin -* = 'U' or 'u', DLAMCH := rmin -* = 'L' or 'l', DLAMCH := emax -* = 'O' or 'o', DLAMCH := rmax -* -* where -* -* eps = relative machine precision -* sfmin = safe minimum, such that 1/sfmin does not overflow -* base = base of the machine -* prec = eps*base -* t = number of (base) digits in the mantissa -* rnd = 1.0 when rounding occurs in addition, 0.0 otherwise -* emin = minimum exponent before (gradual) underflow -* rmin = underflow threshold - base**(emin-1) -* emax = largest exponent before overflow -* rmax = overflow threshold - (base**emax)*(1-eps) -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE PRECISION ONE, ZERO - PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) -* .. -* .. Local Scalars .. - LOGICAL FIRST, LRND - INTEGER BETA, IMAX, IMIN, IT - DOUBLE PRECISION BASE, EMAX, EMIN, EPS, PREC, RMACH, RMAX, RMIN, - $ RND, SFMIN, SMALL, T -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL DLAMC2 -* .. -* .. Save statement .. - SAVE FIRST, EPS, SFMIN, BASE, T, RND, EMIN, RMIN, - $ EMAX, RMAX, PREC -* .. -* .. Data statements .. - DATA FIRST / .TRUE. / -* .. -* .. Executable Statements .. -* - IF( FIRST ) THEN - FIRST = .FALSE. - CALL DLAMC2( BETA, IT, LRND, EPS, IMIN, RMIN, IMAX, RMAX ) - BASE = BETA - T = IT - IF( LRND ) THEN - RND = ONE - EPS = ( BASE**( 1-IT ) ) / 2 - ELSE - RND = ZERO - EPS = BASE**( 1-IT ) - END IF - PREC = EPS*BASE - EMIN = IMIN - EMAX = IMAX - SFMIN = RMIN - SMALL = ONE / RMAX - IF( SMALL.GE.SFMIN ) THEN -* -* Use SMALL plus a bit, to avoid the possibility of rounding -* causing overflow when computing 1/sfmin. -* - SFMIN = SMALL*( ONE+EPS ) - END IF - END IF -* - IF( LSAME( CMACH, 'E' ) ) THEN - RMACH = EPS - ELSE IF( LSAME( CMACH, 'S' ) ) THEN - RMACH = SFMIN - ELSE IF( LSAME( CMACH, 'B' ) ) THEN - RMACH = BASE - ELSE IF( LSAME( CMACH, 'P' ) ) THEN - RMACH = PREC - ELSE IF( LSAME( CMACH, 'N' ) ) THEN - RMACH = T - ELSE IF( LSAME( CMACH, 'R' ) ) THEN - RMACH = RND - ELSE IF( LSAME( CMACH, 'M' ) ) THEN - RMACH = EMIN - ELSE IF( LSAME( CMACH, 'U' ) ) THEN - RMACH = RMIN - ELSE IF( LSAME( CMACH, 'L' ) ) THEN - RMACH = EMAX - ELSE IF( LSAME( CMACH, 'O' ) ) THEN - RMACH = RMAX - END IF -* - DLAMCH = RMACH - RETURN -* -* End of DLAMCH -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC1( BETA, T, RND, IEEE1 ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - LOGICAL IEEE1, RND - INTEGER BETA, T -* .. -* -* Purpose -* ======= -* -* DLAMC1 determines the machine parameters given by BETA, T, RND, and -* IEEE1. -* -* Arguments -* ========= -* -* BETA (output) INTEGER -* The base of the machine. -* -* T (output) INTEGER -* The number of ( BETA ) digits in the mantissa. -* -* RND (output) LOGICAL -* Specifies whether proper rounding ( RND = .TRUE. ) or -* chopping ( RND = .FALSE. ) occurs in addition. This may not -* be a reliable guide to the way in which the machine performs -* its arithmetic. -* -* IEEE1 (output) LOGICAL -* Specifies whether rounding appears to be done in the IEEE -* 'round to nearest' style. -* -* Further Details -* =============== -* -* The routine is based on the routine ENVRON by Malcolm and -* incorporates suggestions by Gentleman and Marovich. See -* -* Malcolm M. A. (1972) Algorithms to reveal properties of -* floating-point arithmetic. Comms. of the ACM, 15, 949-951. -* -* Gentleman W. M. and Marovich S. B. (1974) More on algorithms -* that reveal properties of floating point arithmetic units. -* Comms. of the ACM, 17, 276-277. -* -* ===================================================================== -* -* .. Local Scalars .. - LOGICAL FIRST, LIEEE1, LRND - INTEGER LBETA, LT - DOUBLE PRECISION A, B, C, F, ONE, QTR, SAVEC, T1, T2 -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. Save statement .. - SAVE FIRST, LIEEE1, LBETA, LRND, LT -* .. -* .. Data statements .. - DATA FIRST / .TRUE. / -* .. -* .. Executable Statements .. -* - IF( FIRST ) THEN - FIRST = .FALSE. - ONE = 1 -* -* LBETA, LIEEE1, LT and LRND are the local values of BETA, -* IEEE1, T and RND. -* -* Throughout this routine we use the function DLAMC3 to ensure -* that relevant values are stored and not held in registers, or -* are not affected by optimizers. -* -* Compute a = 2.0**m with the smallest positive integer m such -* that -* -* fl( a + 1.0 ) = a. -* - A = 1 - C = 1 -* -*+ WHILE( C.EQ.ONE )LOOP - 10 CONTINUE - IF( C.EQ.ONE ) THEN - A = 2*A - C = DLAMC3( A, ONE ) - C = DLAMC3( C, -A ) - GO TO 10 - END IF -*+ END WHILE -* -* Now compute b = 2.0**m with the smallest positive integer m -* such that -* -* fl( a + b ) .gt. a. -* - B = 1 - C = DLAMC3( A, B ) -* -*+ WHILE( C.EQ.A )LOOP - 20 CONTINUE - IF( C.EQ.A ) THEN - B = 2*B - C = DLAMC3( A, B ) - GO TO 20 - END IF -*+ END WHILE -* -* Now compute the base. a and c are neighbouring floating point -* numbers in the interval ( beta**t, beta**( t + 1 ) ) and so -* their difference is beta. Adding 0.25 to c is to ensure that it -* is truncated to beta and not ( beta - 1 ). -* - QTR = ONE / 4 - SAVEC = C - C = DLAMC3( C, -A ) - LBETA = C + QTR -* -* Now determine whether rounding or chopping occurs, by adding a -* bit less than beta/2 and a bit more than beta/2 to a. -* - B = LBETA - F = DLAMC3( B / 2, -B / 100 ) - C = DLAMC3( F, A ) - IF( C.EQ.A ) THEN - LRND = .TRUE. - ELSE - LRND = .FALSE. - END IF - F = DLAMC3( B / 2, B / 100 ) - C = DLAMC3( F, A ) - IF( ( LRND ) .AND. ( C.EQ.A ) ) - $ LRND = .FALSE. -* -* Try and decide whether rounding is done in the IEEE 'round to -* nearest' style. B/2 is half a unit in the last place of the two -* numbers A and SAVEC. Furthermore, A is even, i.e. has last bit -* zero, and SAVEC is odd. Thus adding B/2 to A should not change -* A, but adding B/2 to SAVEC should change SAVEC. -* - T1 = DLAMC3( B / 2, A ) - T2 = DLAMC3( B / 2, SAVEC ) - LIEEE1 = ( T1.EQ.A ) .AND. ( T2.GT.SAVEC ) .AND. LRND -* -* Now find the mantissa, t. It should be the integer part of -* log to the base beta of a, however it is safer to determine t -* by powering. So we find t as the smallest positive integer for -* which -* -* fl( beta**t + 1.0 ) = 1.0. -* - LT = 0 - A = 1 - C = 1 -* -*+ WHILE( C.EQ.ONE )LOOP - 30 CONTINUE - IF( C.EQ.ONE ) THEN - LT = LT + 1 - A = A*LBETA - C = DLAMC3( A, ONE ) - C = DLAMC3( C, -A ) - GO TO 30 - END IF -*+ END WHILE -* - END IF -* - BETA = LBETA - T = LT - RND = LRND - IEEE1 = LIEEE1 - RETURN -* -* End of DLAMC1 -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC2( BETA, T, RND, EPS, EMIN, RMIN, EMAX, RMAX ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - LOGICAL RND - INTEGER BETA, EMAX, EMIN, T - DOUBLE PRECISION EPS, RMAX, RMIN -* .. -* -* Purpose -* ======= -* -* DLAMC2 determines the machine parameters specified in its argument -* list. -* -* Arguments -* ========= -* -* BETA (output) INTEGER -* The base of the machine. -* -* T (output) INTEGER -* The number of ( BETA ) digits in the mantissa. -* -* RND (output) LOGICAL -* Specifies whether proper rounding ( RND = .TRUE. ) or -* chopping ( RND = .FALSE. ) occurs in addition. This may not -* be a reliable guide to the way in which the machine performs -* its arithmetic. -* -* EPS (output) DOUBLE PRECISION -* The smallest positive number such that -* -* fl( 1.0 - EPS ) .LT. 1.0, -* -* where fl denotes the computed value. -* -* EMIN (output) INTEGER -* The minimum exponent before (gradual) underflow occurs. -* -* RMIN (output) DOUBLE PRECISION -* The smallest normalized number for the machine, given by -* BASE**( EMIN - 1 ), where BASE is the floating point value -* of BETA. -* -* EMAX (output) INTEGER -* The maximum exponent before overflow occurs. -* -* RMAX (output) DOUBLE PRECISION -* The largest positive number for the machine, given by -* BASE**EMAX * ( 1 - EPS ), where BASE is the floating point -* value of BETA. -* -* Further Details -* =============== -* -* The computation of EPS is based on a routine PARANOIA by -* W. Kahan of the University of California at Berkeley. -* -* ===================================================================== -* -* .. Local Scalars .. - LOGICAL FIRST, IEEE, IWARN, LIEEE1, LRND - INTEGER GNMIN, GPMIN, I, LBETA, LEMAX, LEMIN, LT, - $ NGNMIN, NGPMIN - DOUBLE PRECISION A, B, C, HALF, LEPS, LRMAX, LRMIN, ONE, RBASE, - $ SIXTH, SMALL, THIRD, TWO, ZERO -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. External Subroutines .. - EXTERNAL DLAMC1, DLAMC4, DLAMC5 -* .. -* .. Intrinsic Functions .. - INTRINSIC ABS, MAX, MIN -* .. -* .. Save statement .. - SAVE FIRST, IWARN, LBETA, LEMAX, LEMIN, LEPS, LRMAX, - $ LRMIN, LT -* .. -* .. Data statements .. - DATA FIRST / .TRUE. / , IWARN / .FALSE. / -* .. -* .. Executable Statements .. -* - IF( FIRST ) THEN - FIRST = .FALSE. - ZERO = 0 - ONE = 1 - TWO = 2 -* -* LBETA, LT, LRND, LEPS, LEMIN and LRMIN are the local values of -* BETA, T, RND, EPS, EMIN and RMIN. -* -* Throughout this routine we use the function DLAMC3 to ensure -* that relevant values are stored and not held in registers, or -* are not affected by optimizers. -* -* DLAMC1 returns the parameters LBETA, LT, LRND and LIEEE1. -* - CALL DLAMC1( LBETA, LT, LRND, LIEEE1 ) -* -* Start to find EPS. -* - B = LBETA - A = B**( -LT ) - LEPS = A -* -* Try some tricks to see whether or not this is the correct EPS. -* - B = TWO / 3 - HALF = ONE / 2 - SIXTH = DLAMC3( B, -HALF ) - THIRD = DLAMC3( SIXTH, SIXTH ) - B = DLAMC3( THIRD, -HALF ) - B = DLAMC3( B, SIXTH ) - B = ABS( B ) - IF( B.LT.LEPS ) - $ B = LEPS -* - LEPS = 1 -* -*+ WHILE( ( LEPS.GT.B ).AND.( B.GT.ZERO ) )LOOP - 10 CONTINUE - IF( ( LEPS.GT.B ) .AND. ( B.GT.ZERO ) ) THEN - LEPS = B - C = DLAMC3( HALF*LEPS, ( TWO**5 )*( LEPS**2 ) ) - C = DLAMC3( HALF, -C ) - B = DLAMC3( HALF, C ) - C = DLAMC3( HALF, -B ) - B = DLAMC3( HALF, C ) - GO TO 10 - END IF -*+ END WHILE -* - IF( A.LT.LEPS ) - $ LEPS = A -* -* Computation of EPS complete. -* -* Now find EMIN. Let A = + or - 1, and + or - (1 + BASE**(-3)). -* Keep dividing A by BETA until (gradual) underflow occurs. This -* is detected when we cannot recover the previous A. -* - RBASE = ONE / LBETA - SMALL = ONE - DO 20 I = 1, 3 - SMALL = DLAMC3( SMALL*RBASE, ZERO ) - 20 CONTINUE - A = DLAMC3( ONE, SMALL ) - CALL DLAMC4( NGPMIN, ONE, LBETA ) - CALL DLAMC4( NGNMIN, -ONE, LBETA ) - CALL DLAMC4( GPMIN, A, LBETA ) - CALL DLAMC4( GNMIN, -A, LBETA ) - IEEE = .FALSE. -* - IF( ( NGPMIN.EQ.NGNMIN ) .AND. ( GPMIN.EQ.GNMIN ) ) THEN - IF( NGPMIN.EQ.GPMIN ) THEN - LEMIN = NGPMIN -* ( Non twos-complement machines, no gradual underflow; -* e.g., VAX ) - ELSE IF( ( GPMIN-NGPMIN ).EQ.3 ) THEN - LEMIN = NGPMIN - 1 + LT - IEEE = .TRUE. -* ( Non twos-complement machines, with gradual underflow; -* e.g., IEEE standard followers ) - ELSE - LEMIN = MIN( NGPMIN, GPMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -* - ELSE IF( ( NGPMIN.EQ.GPMIN ) .AND. ( NGNMIN.EQ.GNMIN ) ) THEN - IF( ABS( NGPMIN-NGNMIN ).EQ.1 ) THEN - LEMIN = MAX( NGPMIN, NGNMIN ) -* ( Twos-complement machines, no gradual underflow; -* e.g., CYBER 205 ) - ELSE - LEMIN = MIN( NGPMIN, NGNMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -* - ELSE IF( ( ABS( NGPMIN-NGNMIN ).EQ.1 ) .AND. - $ ( GPMIN.EQ.GNMIN ) ) THEN - IF( ( GPMIN-MIN( NGPMIN, NGNMIN ) ).EQ.3 ) THEN - LEMIN = MAX( NGPMIN, NGNMIN ) - 1 + LT -* ( Twos-complement machines with gradual underflow; -* no known machine ) - ELSE - LEMIN = MIN( NGPMIN, NGNMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -* - ELSE - LEMIN = MIN( NGPMIN, NGNMIN, GPMIN, GNMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -*** -* Comment out this if block if EMIN is ok - IF( IWARN ) THEN - FIRST = .TRUE. - WRITE( 6, FMT = 9999 )LEMIN - END IF -*** -* -* Assume IEEE arithmetic if we found denormalised numbers above, -* or if arithmetic seems to round in the IEEE style, determined -* in routine DLAMC1. A true IEEE machine should have both things -* true; however, faulty machines may have one or the other. -* - IEEE = IEEE .OR. LIEEE1 -* -* Compute RMIN by successive division by BETA. We could compute -* RMIN as BASE**( EMIN - 1 ), but some machines underflow during -* this computation. -* - LRMIN = 1 - DO 30 I = 1, 1 - LEMIN - LRMIN = DLAMC3( LRMIN*RBASE, ZERO ) - 30 CONTINUE -* -* Finally, call DLAMC5 to compute EMAX and RMAX. -* - CALL DLAMC5( LBETA, LT, LEMIN, IEEE, LEMAX, LRMAX ) - END IF -* - BETA = LBETA - T = LT - RND = LRND - EPS = LEPS - EMIN = LEMIN - RMIN = LRMIN - EMAX = LEMAX - RMAX = LRMAX -* - RETURN -* - 9999 FORMAT( / / ' WARNING. The value EMIN may be incorrect:-', - $ ' EMIN = ', I8, / - $ ' If, after inspection, the value EMIN looks', - $ ' acceptable please comment out ', - $ / ' the IF block as marked within the code of routine', - $ ' DLAMC2,', / ' otherwise supply EMIN explicitly.', / ) -* -* End of DLAMC2 -* - END -* -************************************************************************ -* - DOUBLE PRECISION FUNCTION DLAMC3( A, B ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - DOUBLE PRECISION A, B -* .. -* -* Purpose -* ======= -* -* DLAMC3 is intended to force A and B to be stored prior to doing -* the addition of A and B , for use in situations where optimizers -* might hold one of these in a register. -* -* Arguments -* ========= -* -* A, B (input) DOUBLE PRECISION -* The values A and B. -* -* ===================================================================== -* -* .. Executable Statements .. -* - DLAMC3 = A + B -* - RETURN -* -* End of DLAMC3 -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC4( EMIN, START, BASE ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - INTEGER BASE, EMIN - DOUBLE PRECISION START -* .. -* -* Purpose -* ======= -* -* DLAMC4 is a service routine for DLAMC2. -* -* Arguments -* ========= -* -* EMIN (output) EMIN -* The minimum exponent before (gradual) underflow, computed by -* setting A = START and dividing by BASE until the previous A -* can not be recovered. -* -* START (input) DOUBLE PRECISION -* The starting point for determining EMIN. -* -* BASE (input) INTEGER -* The base of the machine. -* -* ===================================================================== -* -* .. Local Scalars .. - INTEGER I - DOUBLE PRECISION A, B1, B2, C1, C2, D1, D2, ONE, RBASE, ZERO -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. Executable Statements .. -* - A = START - ONE = 1 - RBASE = ONE / BASE - ZERO = 0 - EMIN = 1 - B1 = DLAMC3( A*RBASE, ZERO ) - C1 = A - C2 = A - D1 = A - D2 = A -*+ WHILE( ( C1.EQ.A ).AND.( C2.EQ.A ).AND. -* $ ( D1.EQ.A ).AND.( D2.EQ.A ) )LOOP - 10 CONTINUE - IF( ( C1.EQ.A ) .AND. ( C2.EQ.A ) .AND. ( D1.EQ.A ) .AND. - $ ( D2.EQ.A ) ) THEN - EMIN = EMIN - 1 - A = B1 - B1 = DLAMC3( A / BASE, ZERO ) - C1 = DLAMC3( B1*BASE, ZERO ) - D1 = ZERO - DO 20 I = 1, BASE - D1 = D1 + B1 - 20 CONTINUE - B2 = DLAMC3( A*RBASE, ZERO ) - C2 = DLAMC3( B2 / RBASE, ZERO ) - D2 = ZERO - DO 30 I = 1, BASE - D2 = D2 + B2 - 30 CONTINUE - GO TO 10 - END IF -*+ END WHILE -* - RETURN -* -* End of DLAMC4 -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC5( BETA, P, EMIN, IEEE, EMAX, RMAX ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - LOGICAL IEEE - INTEGER BETA, EMAX, EMIN, P - DOUBLE PRECISION RMAX -* .. -* -* Purpose -* ======= -* -* DLAMC5 attempts to compute RMAX, the largest machine floating-point -* number, without overflow. It assumes that EMAX + abs(EMIN) sum -* approximately to a power of 2. It will fail on machines where this -* assumption does not hold, for example, the Cyber 205 (EMIN = -28625, -* EMAX = 28718). It will also fail if the value supplied for EMIN is -* too large (i.e. too close to zero), probably with overflow. -* -* Arguments -* ========= -* -* BETA (input) INTEGER -* The base of floating-point arithmetic. -* -* P (input) INTEGER -* The number of base BETA digits in the mantissa of a -* floating-point value. -* -* EMIN (input) INTEGER -* The minimum exponent before (gradual) underflow. -* -* IEEE (input) LOGICAL -* A logical flag specifying whether or not the arithmetic -* system is thought to comply with the IEEE standard. -* -* EMAX (output) INTEGER -* The largest exponent before overflow -* -* RMAX (output) DOUBLE PRECISION -* The largest machine floating-point number. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE PRECISION ZERO, ONE - PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 ) -* .. -* .. Local Scalars .. - INTEGER EXBITS, EXPSUM, I, LEXP, NBITS, TRY, UEXP - DOUBLE PRECISION OLDY, RECBAS, Y, Z -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. Intrinsic Functions .. - INTRINSIC MOD -* .. -* .. Executable Statements .. -* -* First compute LEXP and UEXP, two powers of 2 that bound -* abs(EMIN). We then assume that EMAX + abs(EMIN) will sum -* approximately to the bound that is closest to abs(EMIN). -* (EMAX is the exponent of the required number RMAX). -* - LEXP = 1 - EXBITS = 1 - 10 CONTINUE - TRY = LEXP*2 - IF( TRY.LE.( -EMIN ) ) THEN - LEXP = TRY - EXBITS = EXBITS + 1 - GO TO 10 - END IF - IF( LEXP.EQ.-EMIN ) THEN - UEXP = LEXP - ELSE - UEXP = TRY - EXBITS = EXBITS + 1 - END IF -* -* Now -LEXP is less than or equal to EMIN, and -UEXP is greater -* than or equal to EMIN. EXBITS is the number of bits needed to -* store the exponent. -* - IF( ( UEXP+EMIN ).GT.( -LEXP-EMIN ) ) THEN - EXPSUM = 2*LEXP - ELSE - EXPSUM = 2*UEXP - END IF -* -* EXPSUM is the exponent range, approximately equal to -* EMAX - EMIN + 1 . -* - EMAX = EXPSUM + EMIN - 1 - NBITS = 1 + EXBITS + P -* -* NBITS is the total number of bits needed to store a -* floating-point number. -* - IF( ( MOD( NBITS, 2 ).EQ.1 ) .AND. ( BETA.EQ.2 ) ) THEN -* -* Either there are an odd number of bits used to store a -* floating-point number, which is unlikely, or some bits are -* not used in the representation of numbers, which is possible, -* (e.g. Cray machines) or the mantissa has an implicit bit, -* (e.g. IEEE machines, Dec Vax machines), which is perhaps the -* most likely. We have to assume the last alternative. -* If this is true, then we need to reduce EMAX by one because -* there must be some way of representing zero in an implicit-bit -* system. On machines like Cray, we are reducing EMAX by one -* unnecessarily. -* - EMAX = EMAX - 1 - END IF -* - IF( IEEE ) THEN -* -* Assume we are on an IEEE machine which reserves one exponent -* for infinity and NaN. -* - EMAX = EMAX - 1 - END IF -* -* Now create RMAX, the largest machine number, which should -* be equal to (1.0 - BETA**(-P)) * BETA**EMAX . -* -* First compute 1.0 - BETA**(-P), being careful that the -* result is less than 1.0 . -* - RECBAS = ONE / BETA - Z = BETA - ONE - Y = ZERO - DO 20 I = 1, P - Z = Z*RECBAS - IF( Y.LT.ONE ) - $ OLDY = Y - Y = DLAMC3( Y, Z ) - 20 CONTINUE - IF( Y.GE.ONE ) - $ Y = OLDY -* -* Now multiply by BETA**EMAX to get RMAX. -* - DO 30 I = 1, EMAX - Y = DLAMC3( Y*BETA, ZERO ) - 30 CONTINUE -* - RMAX = Y - RETURN -* -* End of DLAMC5 -* - END - LOGICAL FUNCTION LSAME( CA, CB ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* September 30, 1994 -* -* .. Scalar Arguments .. - CHARACTER CA, CB -* .. -* -* Purpose -* ======= -* -* LSAME returns .TRUE. if CA is the same letter as CB regardless of -* case. -* -* Arguments -* ========= -* -* CA (input) CHARACTER*1 -* CB (input) CHARACTER*1 -* CA and CB specify the single characters to be compared. -* -* ===================================================================== -* -* .. Intrinsic Functions .. - INTRINSIC ICHAR -* .. -* .. Local Scalars .. - INTEGER INTA, INTB, ZCODE -* .. -* .. Executable Statements .. -* -* Test if the characters are equal -* - LSAME = CA.EQ.CB - IF( LSAME ) - $ RETURN -* -* Now test for equivalence if both characters are alphabetic. -* - ZCODE = ICHAR( 'Z' ) -* -* Use 'Z' rather than 'A' so that ASCII can be detected on Prime -* machines, on which ICHAR returns a value with bit 8 set. -* ICHAR('A') on Prime machines returns 193 which is the same as -* ICHAR('A') on an EBCDIC machine. -* - INTA = ICHAR( CA ) - INTB = ICHAR( CB ) -* - IF( ZCODE.EQ.90 .OR. ZCODE.EQ.122 ) THEN -* -* ASCII is assumed - ZCODE is the ASCII code of either lower or -* upper case 'Z'. -* - IF( INTA.GE.97 .AND. INTA.LE.122 ) INTA = INTA - 32 - IF( INTB.GE.97 .AND. INTB.LE.122 ) INTB = INTB - 32 -* - ELSE IF( ZCODE.EQ.233 .OR. ZCODE.EQ.169 ) THEN -* -* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or -* upper case 'Z'. -* - IF( INTA.GE.129 .AND. INTA.LE.137 .OR. - $ INTA.GE.145 .AND. INTA.LE.153 .OR. - $ INTA.GE.162 .AND. INTA.LE.169 ) INTA = INTA + 64 - IF( INTB.GE.129 .AND. INTB.LE.137 .OR. - $ INTB.GE.145 .AND. INTB.LE.153 .OR. - $ INTB.GE.162 .AND. INTB.LE.169 ) INTB = INTB + 64 -* - ELSE IF( ZCODE.EQ.218 .OR. ZCODE.EQ.250 ) THEN -* -* ASCII is assumed, on Prime machines - ZCODE is the ASCII code -* plus 128 of either lower or upper case 'Z'. -* - IF( INTA.GE.225 .AND. INTA.LE.250 ) INTA = INTA - 32 - IF( INTB.GE.225 .AND. INTB.LE.250 ) INTB = INTB - 32 - END IF - LSAME = INTA.EQ.INTB -* -* RETURN -* -* End of LSAME -* - END diff -u -u cash.orig/mebdfi.f cash/mebdfi.f --- cash.orig/mebdfi.f 2007-11-16 19:00:20.000000000 +0100 +++ cash/mebdfi.f 2008-01-19 17:24:20.000000000 +0100 @@ -58,11 +58,11 @@ C C SEPTEMBER 20th 1999: FIRST RELEASE C -C OVDRIV +C I_OVDRIV C A PACKAGE FOR THE SOLUTION OF THE INITIAL VALUE PROBLEM C FOR SYSTEMS OF IMPLICIT DIFFERENTIAL ALGEBRAIC EQUATIONS c G(t,Y,Y')=0, Y=(Y(1),Y(2),Y(3),.....,Y(N)). -C SUBROUTINE OVDRIV IS A DRIVER ROUTINE FOR THIS PACKAGE. +C SUBROUTINE I_OVDRIV IS A DRIVER ROUTINE FOR THIS PACKAGE. C C REFERENCES C @@ -82,7 +82,7 @@ C SPRINGER 1996, page 267. C C ---------------------------------------------------------------- -C OVDRIV IS TO BE CALLED ONCE FOR EACH OUTPUT VALUE OF T, AND +C I_OVDRIV IS TO BE CALLED ONCE FOR EACH OUTPUT VALUE OF T, AND C IN TURN MAKES REPEATED CALLS TO THE CORE INTEGRATOR STIFF. C C THE INPUT PARAMETERS ARE .. @@ -158,7 +158,7 @@ C SHOULD BE NON-NEGATIVE. IF ITOL = 1 THEN SINGLE STEP ERROR C ESTIMATES DIVIDED BY YMAX(I) WILL BE KEPT LESS THAN 1 C IN ROOT-MEAN-SQUARE NORM. THE VECTOR YMAX OF WEIGHTS IS -C COMPUTED IN OVDRIV. INITIALLY YMAX(I) IS SET AS +C COMPUTED IN I_OVDRIV. INITIALLY YMAX(I) IS SET AS C THE MAXIMUM OF 1 AND ABS(Y(I)). THEREAFTER YMAX(I) IS C THE LARGEST VALUE OF ABS(Y(I)) SEEN SO FAR, OR THE C INITIAL VALUE YMAX(I) IF THAT IS LARGER. @@ -242,23 +242,23 @@ C -12 INSUFFICIENT INTEGER WORKSPACE FOR THE INTEGRATION C C -C IN ADDITION TO OVDRIVE, THE FOLLOWING ROUTINES ARE PROVIDED +C IN ADDITION TO I_OVDRIVE, THE FOLLOWING ROUTINES ARE PROVIDED C IN THE PACKAGE.. C -C INTERP( - ) INTERPOLATES TO GET THE OUTPUT VALUES +C I_INTERP( - ) INTERPOLATES TO GET THE OUTPUT VALUES C AT T=TOUT FROM THE DATA IN THE Y ARRAY. -C STIFF( - ) IS THE CORE INTEGRATOR ROUTINE. IT PERFORMS A +C I_STIFF( - ) IS THE CORE INTEGRATOR ROUTINE. IT PERFORMS A C SINGLE STEP AND ASSOCIATED ERROR CONTROL. -C COSET( - ) SETS COEFFICIENTS FOR BACKWARD DIFFERENTIATION +C I_COSET( - ) SETS COEFFICIENTS FOR BACKWARD DIFFERENTIATION C SCHEMES FOR USE IN THE CORE INTEGRATOR. -C PSET( - ) COMPUTES AND PROCESSES THE NEWTON ITERATION +C I_PSET( - ) COMPUTES AND PROCESSES THE NEWTON ITERATION C MATRIX DG/DY + (1/(H*BETA))DG/DY' -C DEC( - ) PERFORMS AN LU DECOMPOSITION ON A MATRIX. -C SOL( - ) SOLVES LINEAR SYSTEMS A*X = B AFTER DEC +C I_DEC( - ) PERFORMS AN LU DECOMPOSITION ON A MATRIX. +C I_SOL( - ) SOLVES LINEAR SYSTEMS A*X = B AFTER I_DEC C HAS BEEN CALLED FOR THE MATRIX A -C DGBFA ( - ) FACTORS A DOUBLE PRECISION BAND MATRIX BY +C I_DGBFA ( - ) FACTORS A DOUBLE PRECISION BAND MATRIX BY C ELIMINATION. -C DGBSL ( - ) SOLVES A BANDED LINEAR SYSTEM A*x=b +C I_DGBSL ( - ) SOLVES A BANDED LINEAR SYSTEM A*x=b C C ALSO SUPPLIED ARE THE BLAS ROUTINES C @@ -330,7 +330,7 @@ C >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> C THIS SUBROUTINE IS FOR THE PURPOSE * C OF SPLITTING UP THE WORK ARRAYS WORK AND IWORK * -C FOR USE INSIDE THE INTEGRATOR STIFF * +C FOR USE INSIDE THE INTEGRATOR I_STIFF * C <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C .. SCALAR ARGUMENTS .. @@ -346,7 +346,7 @@ C COMMON BLOCKS C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL OVDRIV,PDERV,RESID + EXTERNAL I_OVDRIV,PDERV,RESID C .. C .. SAVE STATEMENT .. SAVE I1,I2,I3,I4,I5,I6,I7,I8,I9,I10,I11 @@ -397,7 +397,7 @@ c THE ERROR FLAG IS INITIALISED c - CALL OVDRIV(N,T0,HO,Y0,YPRIME,TOUT,TEND,MF,IDID,LOUT,WORK(3), + CALL I_OVDRIV(N,T0,HO,Y0,YPRIME,TOUT,TEND,MF,IDID,LOUT,WORK(3), + WORK(I1),WORK(I2),WORK(I3),WORK(I4),WORK(I5),WORK(I6), + WORK(I7),WORK(I8),WORK(I9),WORK(I10),IWORK(15), + MBND,IWORK(1),IWORK(2),IWORK(3),MAXDER,ITOL,RTOL,ATOL,RPAR, @@ -428,7 +428,7 @@ END C-------------------------------------------------------------------------- C - SUBROUTINE OVDRIV(N,T0,HO,Y0,YPRIME,TOUT,TEND,MF,IDID,LOUT,Y, + SUBROUTINE I_OVDRIV(N,T0,HO,Y0,YPRIME,TOUT,TEND,MF,IDID,LOUT,Y, + YHOLD,YNHOLD,YMAX,ERRORS,SAVE1,SAVE2,SCALE,ARH,PW,PWCOPY, + IPIV,MBND,NIND1,NIND2,NIND3,MAXDER,ITOL,RTOL,ATOL,RPAR, + IPAR,PDERV,RESID,NQUSED,NSTEP,NFAIL,NRE,NJE,NDEC,NBSOL, @@ -452,7 +452,7 @@ INTEGER I,KGO,NHCUT C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL INTERP,STIFF,PDERV,RESID + EXTERNAL I_INTERP,I_STIFF,PDERV,RESID C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DABS,DMAX1 @@ -468,7 +468,7 @@ HMAX = DABS(TEND-T0)/10.0D+0 IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT THE OUTPUT POINT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IDID = KFLAG T0 = TOUT HO = H @@ -486,7 +486,7 @@ IF (((T-TOUT)*H.GE.0.0D+0) .OR. (DABS(T-TOUT).LE. + 100.0D+0*UROUND*HMAX)) THEN C HAVE OVERSHOT THE OUTPUT POINT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) T0 = TOUT HO = H IDID = KFLAG @@ -513,7 +513,7 @@ IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT TOUT WRITE (LOUT,9080) T,TOUT,H - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) HO = H T0 = TOUT IDID = -5 @@ -527,7 +527,7 @@ T0 = T IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT,SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IDID = KFLAG T0 = TOUT HO = H @@ -660,7 +660,7 @@ 20 IF ((T+H).EQ.T) THEN WRITE (LOUT,9000) END IF - CALL STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND, + CALL I_STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND, + NIND1,NIND2,NIND3,T,TOUT,TEND,Y,YPRIME,N, + YMAX,ERRORS,SAVE1,SAVE2,SCALE,PW,PWCOPY,YHOLD, + YNHOLD,ARH,IPIV,LOUT,MAXDER,ITOL,RTOL,ATOL,RPAR,IPAR, @@ -672,7 +672,7 @@ C ENDIF KGO = 1 - KFLAG IF (KGO.EQ.1) THEN -C NORMAL RETURN FROM STIFF +C NORMAL RETURN FROM I_STIFF GO TO 30 ELSE IF (KGO.EQ.2) THEN @@ -708,7 +708,7 @@ C FOR ANY OTHER VALUE OF IDID, CONTROL RETURNS TO THE INTEGRATOR C UNLESS TOUT HAS BEEN REACHED. THEN INTERPOLATED VALUES OF Y ARE C COMPUTED AND STORED IN Y0 ON RETURN. -C IF INTERPOLATION IS NOT DESIRED, THE CALL TO INTERP SHOULD BE +C IF INTERPOLATION IS NOT DESIRED, THE CALL TO I_INTERP SHOULD BE C REMOVED AND CONTROL TRANSFERRED TO STATEMENT 500 INSTEAD OF 520. C -------------------------------------------------------------------- IF(NSTEP.GT.MAXSTP) THEN @@ -749,7 +749,7 @@ IF (((T-TOUT)*H.GE.0.0D+0) .OR. (DABS(T-TOUT).LE. + 100.0D+0*UROUND*HMAX)) THEN C HAVE OVERSHOT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) T0 = TOUT HO = H IDID = KFLAG @@ -766,7 +766,7 @@ ELSE IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT, SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IDID = KFLAG HO = H T0 = TOUT @@ -805,14 +805,14 @@ ELSE C HAVE PASSED TOUT SO INTERPOLATE - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) T0 = TOUT IDID = KFLAG END IF HO = H IF(KFLAG.NE.0) IDID = KFLAG RETURN -C -------------------------- END OF SUBROUTINE OVDRIV ----------------- +C -------------------------- END OF SUBROUTINE I_OVDRIV ----------------- 9000 FORMAT (' WARNING.. T + H = T ON NEXT STEP.') 9010 FORMAT (/,/,' KFLAG = -2 FROM INTEGRATOR AT T = ',E16.8,' H =', + E16.8,/, @@ -848,7 +848,7 @@ END C-------------------------------------------------------------------------- C - SUBROUTINE INTERP(N,JSTART,H,T,Y,TOUT,Y0) + SUBROUTINE I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C .. SCALAR ARGUMENTS .. @@ -875,15 +875,15 @@ 20 CONTINUE 30 CONTINUE RETURN -C -------------- END OF SUBROUTINE INTERP --------------------------- +C -------------- END OF SUBROUTINE I_INTERP --------------------------- END C - SUBROUTINE COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + SUBROUTINE I_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C -------------------------------------------------------------------- -C COSET IS CALLED BY THE INTEGRATOR AND SETS THE COEFFICIENTS USED +C I_COSET IS CALLED BY THE INTEGRATOR AND SETS THE COEFFICIENTS USED C BY THE CONVENTIONAL BACKWARD DIFFERENTIATION SCHEME AND THE C MODIFIED EXTENDED BACKWARD DIFFERENTIATION SCHEME. THE VECTOR C EL OF LENGTH NQ+1 DETERMINES THE BASIC BDF METHOD WHILE THE VECTOR @@ -1013,24 +1013,24 @@ TQ(4) = 0.5D+0*TQ(2)/DBLE(FLOAT(NQ)) IF(NQ.NE.1) TQ(5)=PERTST(NQ-1,1) RETURN -C --------------------- END OF SUBROUTINE COSET --------------------- +C --------------------- END OF SUBROUTINE I_COSET --------------------- END - SUBROUTINE PSET(Y,YPRIME,N,H,T,UROUND,EPSJAC,CON,MITER,MBND, + SUBROUTINE I_PSET(Y,YPRIME,N,H,T,UROUND,EPSJAC,CON,MITER,MBND, + NIND1,NIND2,NIND3,IER,PDERV,RESID,NRENEW,YMAX,SAVE1,SAVE2, + SAVE3,PW,PWCOPY,WRKSPC,IPIV,ITOL,RTOL,ATOL,NPSET,NJE,NRE, + NDEC,IPAR,RPAR,IERR) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C ------------------------------------------------------------------- -C PSET IS CALLED BY STIFF TO COMPUTE AND PROCESS THE MATRIX +C I_PSET IS CALLED BY I_STIFF TO COMPUTE AND PROCESS THE MATRIX C PD=DG/DY + (1/CON)DG/DY'. THIS MATRIX IS THEN SUBJECTED TO LU C DECOMPOSITION IN PREPARATION FOR LATER SOLUTION OF LINEAR SYSTEMS C OF ALGEBRAIC EQUATIONS WITH LU AS THE COEFFICIENT MATRIX. THE C MATRIX PD IS FOUND BY THE USER-SUPPLIED ROUTINE PDERV IF MITER=1 C OR 3 OR BY FINITE DIFFERENCING IF MITER = 2 OR 4. C IN ADDITION TO VARIABLES DESCRIBED PREVIOUSLY, COMMUNICATION WITH -C PSET USES THE FOLLOWING .. +C I_PSET USES THE FOLLOWING .. C EPSJAC = DSQRT(UROUND), USED IN NUMERICAL JACOBIAN INCREMENTS. C ******************************************************************* C THE ARGUMENT NRENEW IS USED TO SIGNAL WHETHER OR NOT @@ -1052,7 +1052,7 @@ INTEGER I,J,J1,JJKK C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL DEC,PDERV,DGBFA,RESID + EXTERNAL I_DEC,PDERV,I_DGBFA,RESID C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DABS,DMAX1,DSQRT @@ -1192,17 +1192,17 @@ NRE=NRE+ MIN(MBND(3),N) C 70 IF (MITER.GT.2) THEN - CALL DGBFA(PW,MBND(4),N,ML,MU,IPIV,IER) + CALL I_DGBFA(PW,MBND(4),N,ML,MU,IPIV,IER) NDEC = NDEC + 1 ELSE - CALL DEC(N,N,PW,IPIV,IER) + CALL I_DEC(N,N,PW,IPIV,IER) NDEC = NDEC + 1 ENDIF RETURN -C ---------------------- END OF SUBROUTINE PSET --------------------- +C ---------------------- END OF SUBROUTINE I_PSET --------------------- END C - SUBROUTINE DEC(N,NDIM,A,IP,IER) + SUBROUTINE I_DEC(N,NDIM,A,IP,IER) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C ------------------------------------------------------------------- @@ -1218,9 +1218,9 @@ C IP(N) = (-1)**(NUMBER OF INTERCHANGES) OR 0. C IER = 0 IF MATRIX IS NON-SINGULAR, OR K IF FOUND TO BE SINGULAR C AT STAGE K. -C USE SOL TO OBTAIN SOLUTION OF LINEAR SYSTEM. +C USE I_SOL TO OBTAIN SOLUTION OF LINEAR SYSTEM. C DETERM(A) = IP(N)*A(1,1)*A(2,2)* . . . *A(N,N). -C IF IP(N) = 0, A IS SINGULAR, SOL WILL DIVIDE BY ZERO. +C IF IP(N) = 0, A IS SINGULAR, I_SOL WILL DIVIDE BY ZERO. C C REFERENCE. C C.B. MOLER, ALGORITHM 423, LINEAR EQUATION SOLVER, C.A.C.M @@ -1279,10 +1279,10 @@ 80 IER = K IP(N) = 0 RETURN -C--------------------- END OF SUBROUTINE DEC ---------------------- +C--------------------- END OF SUBROUTINE I_DEC ---------------------- END C - SUBROUTINE SOL(N,NDIM,A,B,IP) + SUBROUTINE I_SOL(N,NDIM,A,B,IP) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C .. SCALAR ARGUMENTS .. @@ -1305,8 +1305,8 @@ C NDIM = DECLARED DIMENSION OF MATRIX A. C A = TRIANGULARISED MATRIX OBTAINED FROM DEC. C B = RIGHT HAND SIDE VECTOR. -C IP = PIVOT VECTOR OBTAINED FROM DEC. -C DO NOT USE IF DEC HAS SET IER .NE. 0 +C IP = PIVOT VECTOR OBTAINED FROM I_DEC. +C DO NOT USE IF I_DEC HAS SET IER .NE. 0 C OUTPUT.. C B = SOLUTION VECTOR, X. C ------------------------------------------------------------------ @@ -1333,16 +1333,16 @@ 40 CONTINUE 50 B(1) = B(1)/A(1,1) RETURN -C------------------------- END OF SUBROUTINE SOL ------------------ +C------------------------- END OF SUBROUTINE I_SOL ------------------ END C - subroutine dgbfa(abd,lda,n,ml,mu,ipvt,info) + subroutine i_dgbfa(abd,lda,n,ml,mu,ipvt,info) integer lda,n,ml,mu,ipvt(1),info double precision abd(lda,1) c -c dgbfa factors a double precision band matrix by elimination. +c i_dgbfa factors a double precision band matrix by elimination. c -c dgbfa is usually called by dgbco, but it can be called +c i_dgbfa is usually called by dgbco, but it can be called c directly with a saving in time if rcond is not needed. c c on entry @@ -1384,7 +1384,7 @@ c = 0 normal value. c = k if u(k,k) .eq. 0.0 . this is not an error c condition for this subroutine, but it does -c indicate that dgbsl will divide by zero if +c indicate that i_dgbsl will divide by zero if c called. use rcond in dgbco for a reliable c indication of singularity. c @@ -1511,151 +1511,18 @@ return end C-------------------------------------------------------------------------- - subroutine daxpy(n,da,dx,incx,dy,incy) -c -c constant times a vector plus a vector. -c uses unrolled loops for increments equal to one. -c jack dongarra, linpack, 3/11/78. -c - double precision dx(1),dy(1),da - integer i,incx,incy,ix,iy,m,mp1,n -c - if(n.le.0)return - if (da .eq. 0.0d0) return - if(incx.eq.1.and.incy.eq.1)go to 20 -c -c code for unequal increments or equal increments -c not equal to 1 -c - ix = 1 - iy = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - if(incy.lt.0)iy = (-n+1)*incy + 1 - do 10 i = 1,n - dy(iy) = dy(iy) + da*dx(ix) - ix = ix + incx - iy = iy + incy - 10 continue - return -c -c code for both increments equal to 1 -c -c -c clean-up loop -c - 20 m = mod(n,4) - if( m .eq. 0 ) go to 40 - do 30 i = 1,m - dy(i) = dy(i) + da*dx(i) - 30 continue - if( n .lt. 4 ) return - 40 mp1 = m + 1 - do 50 i = mp1,n,4 - dy(i) = dy(i) + da*dx(i) - dy(i + 1) = dy(i + 1) + da*dx(i + 1) - dy(i + 2) = dy(i + 2) + da*dx(i + 2) - dy(i + 3) = dy(i + 3) + da*dx(i + 3) - 50 continue - return - end -C--------------------------------------------------------------------------- - subroutine dscal(n,da,dx,incx) -c -c scales a vector by a constant. -c uses unrolled loops for increment equal to one. -c jack dongarra, linpack, 3/11/78. -c modified to correct problem with negative increment, 8/21/90. -c - double precision da,dx(1) - integer i,incx,ix,m,mp1,n -c - if(n.le.0)return - if(incx.eq.1)go to 20 -c -c code for increment not equal to 1 -c - ix = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - do 10 i = 1,n - dx(ix) = da*dx(ix) - ix = ix + incx - 10 continue - return -c -c code for increment equal to 1 -c -c -c clean-up loop -c - 20 m = mod(n,5) - if( m .eq. 0 ) go to 40 - do 30 i = 1,m - dx(i) = da*dx(i) - 30 continue - if( n .lt. 5 ) return - 40 mp1 = m + 1 - do 50 i = mp1,n,5 - dx(i) = da*dx(i) - dx(i + 1) = da*dx(i + 1) - dx(i + 2) = da*dx(i + 2) - dx(i + 3) = da*dx(i + 3) - dx(i + 4) = da*dx(i + 4) - 50 continue - return - end -C-------------------------------------------------------------------------- - integer function idamax(n,dx,incx) -c -c finds the index of element having max. absolute value. -c jack dongarra, linpack, 3/11/78. -c modified to correct problem with negative increment, 8/21/90. -c - double precision dx(1),dmax - integer i,incx,ix,n -c - idamax = 0 - if( n .lt. 1 ) return - idamax = 1 - if(n.eq.1)return - if(incx.eq.1)go to 20 -c -c code for increment not equal to 1 -c - ix = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - dmax = dabs(dx(ix)) - ix = ix + incx - do 10 i = 2,n - if(dabs(dx(ix)).le.dmax) go to 5 - idamax = i - dmax = dabs(dx(ix)) - 5 ix = ix + incx - 10 continue - return -c -c code for increment equal to 1 -c - 20 dmax = dabs(dx(1)) - do 30 i = 2,n - if(dabs(dx(i)).le.dmax) go to 30 - idamax = i - dmax = dabs(dx(i)) - 30 continue - return - end -C-------------------------------------------------------------------------- - subroutine dgbsl(abd,lda,n,ml,mu,ipvt,b,job) + subroutine i_dgbsl(abd,lda,n,ml,mu,ipvt,b,job) integer lda,n,ml,mu,ipvt(*),job double precision abd(lda,*),b(*) c -c dgbsl solves the double precision band system +c i_dgbsl solves the double precision band system c a * x = b or trans(a) * x = b -c using the factors computed by dgbco or dgbfa. +c using the factors computed by dgbco or i_dgbfa. c c on entry c c abd double precision(lda, n) -c the output from dgbco or dgbfa. +c the output from dgbco or i_dgbfa. c c lda integer c the leading dimension of the array abd . @@ -1670,7 +1537,7 @@ c number of diagonals above the main diagonal. c c ipvt integer(n) -c the pivot vector from dgbco or dgbfa. +c the pivot vector from dgbco or i_dgbfa. c c b double precision(n) c the right hand side vector. @@ -1691,14 +1558,14 @@ c but it is often caused by improper arguments or improper c setting of lda . it will not occur if the subroutines are c called correctly and if dgbco has set rcond .gt. 0.0 -c or dgbfa has set info .eq. 0 . +c or i_dgbfa has set info .eq. 0 . c c to compute inverse(a) * c where c is a matrix c with p columns c call dgbco(abd,lda,n,ml,mu,ipvt,rcond,z) c if (rcond is too small) go to ... c do 10 j = 1, p -c call dgbsl(abd,lda,n,ml,mu,ipvt,c(1,j),0) +c call i_dgbsl(abd,lda,n,ml,mu,ipvt,c(1,j),0) c 10 continue c c linpack. this version dated 08/14/78 . @@ -1780,64 +1647,14 @@ return end C--------------------------------------------------------------------------- - double precision function ddot(n,dx,incx,dy,incy) -c -c forms the dot product of two vectors. -c uses unrolled loops for increments equal to one. -c jack dongarra, linpack, 3/11/78. -c - double precision dx(1),dy(1),dtemp - integer i,incx,incy,ix,iy,m,mp1,n -c - ddot = 0.0d0 - dtemp = 0.0d0 - if(n.le.0)return - if(incx.eq.1.and.incy.eq.1)go to 20 -c -c code for unequal increments or equal increments -c not equal to 1 -c - ix = 1 - iy = 1 - if(incx.lt.0)ix = (-n+1)*incx + 1 - if(incy.lt.0)iy = (-n+1)*incy + 1 - do 10 i = 1,n - dtemp = dtemp + dx(ix)*dy(iy) - ix = ix + incx - iy = iy + incy - 10 continue - ddot = dtemp - return -c -c code for both increments equal to 1 -c -c -c clean-up loop -c - 20 m = mod(n,5) - if( m .eq. 0 ) go to 40 - do 30 i = 1,m - dtemp = dtemp + dx(i)*dy(i) - 30 continue - if( n .lt. 5 ) go to 60 - 40 mp1 = m + 1 - do 50 i = mp1,n,5 - dtemp = dtemp + dx(i)*dy(i) + dx(i + 1)*dy(i + 1) + - * dx(i + 2)*dy(i + 2) + dx(i + 3)*dy(i + 3) + - * dx(i + 4)*dy(i + 4) - 50 continue - 60 ddot = dtemp - return - end -C--------------------------------------------------------------------------- - SUBROUTINE ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + SUBROUTINE I_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C *************************************************** C C THIS ROUTINE CALCULATES ERRORS USED IN TESTS -C IN STIFF . +C IN I_STIFF . C C *************************************************** C .. SCALAR ARGUMENTS .. @@ -1872,7 +1689,7 @@ END C-------------------------------------------------------------------------- - SUBROUTINE PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) + SUBROUTINE I_PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C ********************************************************************** @@ -1903,7 +1720,7 @@ END C------------------------------------------------------------------------ - SUBROUTINE ITRAT2(QQQ,Y,YPRIME,N,T,HBETA,ERRBND,ARH,CRATE,TCRATE + SUBROUTINE I_ITRAT2(QQQ,Y,YPRIME,N,T,HBETA,ERRBND,ARH,CRATE,TCRATE + ,M,WORKED,YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND,NIND1, + NIND2,NIND3,IPIV,LMB,ITOL,RTOL,ATOL,IPAR,RPAR,HUSED,NBSOL, + NRE,NQUSED,RESID,IERR) @@ -1922,7 +1739,7 @@ INTEGER I C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL SOL,DGBSL,RESID + EXTERNAL I_SOL,I_DGBSL,RESID C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DMAX1,DMIN1 @@ -1963,10 +1780,10 @@ C call resid(n,t,y,save2,yprime,ipar,rpar,ierr) IF(MF.GE.23) THEN - CALL DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE2,0) + CALL I_DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE2,0) NBSOL = NBSOL + 1 ELSE - CALL SOL(N,N,PW,SAVE2,IPIV) + CALL I_SOL(N,N,PW,SAVE2,IPIV) NBSOL = NBSOL + 1 ENDIF D = ZERO @@ -1992,10 +1809,10 @@ C IF WE ARE HERE THEN PARTIALS ARE O.K. C IF( MF.GE. 23) THEN - CALL DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE2,0) + CALL I_DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE2,0) NBSOL=NBSOL + 1 ELSE - CALL SOL(N,N,PW,SAVE2,IPIV) + CALL I_SOL(N,N,PW,SAVE2,IPIV) NBSOL = NBSOL + 1 ENDIF C @@ -2043,7 +1860,7 @@ END C-------------------------------------------------------------------------- - SUBROUTINE STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND, + SUBROUTINE I_STIFF(H,HMAX,HMIN,JSTART,KFLAG,MF,MBND, + NIND1,NIND2,NIND3,T,TOUT,TEND,Y,YPRIME,N, + YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,PWCOPY,YHOLD, + YNHOLD,ARH,IPIV,LOUT,MAXDER,ITOL,RTOL,ATOL,RPAR,IPAR, @@ -2052,13 +1869,13 @@ IMPLICIT DOUBLE PRECISION(A-H,O-Z) C ------------------------------------------------------------------ -C THE SUBROUTINE STIFF PERFORMS ONE STEP OF THE INTEGRATION OF AN +C THE SUBROUTINE I_STIFF PERFORMS ONE STEP OF THE INTEGRATION OF AN C INITIAL VALUE PROBLEM FOR A SYSTEM OF C IMPLICIT DIFFERENTIAL ALGEBRAIC EQUATIONS. -C COMMUNICATION WITH STIFF IS DONE WITH THE FOLLOWING VARIABLES.. +C COMMUNICATION WITH I_STIFF IS DONE WITH THE FOLLOWING VARIABLES.. C Y AN N BY LMAX+3 ARRAY CONTAINING THE DEPENDENT VARIABLES C AND THEIR BACKWARD DIFFERENCES. MAXDER (=LMAX-1) IS THE -C MAXIMUM ORDER AVAILABLE. SEE SUBROUTINE COSET. +C MAXIMUM ORDER AVAILABLE. SEE SUBROUTINE I_COSET. C Y(I,J+1) CONTAINS THE JTH BACKWARD DIFFERENCE OF Y(I) C T THE INDEPENDENT VARIABLE. T IS UPDATED ON EACH STEP TAKEN. C H THE STEPSIZE TO BE ATTEMPTED ON THE NEXT STEP. @@ -2068,7 +1885,7 @@ C HMIN THE MINIMUM AND MAXIMUM ABSOLUTE VALUE OF THE STEPSIZE C HMAX TO BE USED FOR THE STEP. THESE MAY BE CHANGED AT ANY C TIME BUT WILL NOT TAKE EFFECT UNTIL THE NEXT H CHANGE. -C RTOL,ATOL THE ERROR BOUNDS. SEE DESCRIPTION IN OVDRIV. +C RTOL,ATOL THE ERROR BOUNDS. SEE DESCRIPTION IN I_OVDRIV. C N THE NUMBER OF FIRST ORDER DIFFERENTIAL EQUATIONS. C MF THE METHOD FLAG. MUST BE SET TO 21,22,23 OR 24 AT PRESENT C KFLAG A COMPLETION FLAG WITH THE FOLLOWING MEANINGS.. @@ -2103,7 +1920,7 @@ C MATRIX WAS FORMED BY A NEW J. C AVOLDJ STORES VALUE FOR AVERAGE CRATE WHEN ITERATION C MATRIX WAS FORMED BY AN OLD J. -C NRENEW FLAG THAT IS USED IN COMMUNICATION WITH SUBROUTINE PSET. +C NRENEW FLAG THAT IS USED IN COMMUNICATION WITH SUBROUTINE I_PSET. C IF NRENEW > 0 THEN FORM A NEW JACOBIAN BEFORE C COMPUTING THE COEFFICIENT MATRIX FOR C THE NEWTON-RAPHSON ITERATION @@ -2132,8 +1949,8 @@ DIMENSION EL(10),ELST(10),TQ(5) C .. C .. EXTERNAL SUBROUTINES .. - EXTERNAL COSET,CPYARY,ERRORS,HCHOSE,ITRAT2, - + PRDICT,PSET,RSCALE,SOL,DGBSL,PDERV,RESID + EXTERNAL I_COSET,I_CPYARY,I_ERRORS,I_HCHOSE,I_ITRAT2, + + I_PRDICT,I_PSET,I_RSCALE,I_SOL,I_DGBSL,PDERV,RESID C .. C .. INTRINSIC FUNCTIONS .. INTRINSIC DABS,DMAX1,DMIN1 @@ -2225,14 +2042,14 @@ HUSED = H C ----------------------------------------------------------------- C IF THE CALLER HAS CHANGED N , THE CONSTANTS E, EDN, EUP -C AND BND MUST BE RESET. E IS A COMPARISON FOR ERRORS AT THE +C AND BND MUST BE RESET. E IS A COMPARISON FOR I_ERRORS AT THE C CURRENT ORDER NQ. EUP IS TO TEST FOR INCREASING THE ORDER, C EDN FOR DECREASING THE ORDER. BND IS USED TO TEST FOR CONVERGENCE C OF THE CORRECTOR ITERATES. IF THE CALLER HAS CHANGED H, Y MUST C BE RE-SCALED. IF H IS CHANGED, IDOUB IS SET TO L+1 TO PREVENT C FURTHER CHANGES IN H FOR THAT MANY STEPS. C ----------------------------------------------------------------- - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL I_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) LMAX = MAXDER + 1 RC = RC*EL(1)/OLDLO OLDLO = EL(1) @@ -2243,14 +2060,14 @@ C NRENEW AND NEWPAR ARE TO INSTRUCT ROUTINE THAT C WE WISH A NEW J TO BE CALCULATED FOR THIS STEP. C ***************************************************** - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL I_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) DO 20 I = 1,N ARH(I) = EL(2)*Y(I,1) 20 CONTINUE - CALL CPYARY(N*L,Y,YHOLD) + CALL I_CPYARY(N*L,Y,YHOLD) QI = H*EL(1) QQ = ONE/QI - CALL PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) + CALL I_PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) IF(IERR.NE.0) THEN H=H/2 IERR = 0 @@ -2263,7 +2080,7 @@ C >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> C DIFFERENT PARAMETERS ON THIS CALL < C <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - 30 CALL CPYARY(N*L,YHOLD,Y) + 30 CALL I_CPYARY(N*L,YHOLD,Y) IF (MF.NE.MFOLD) THEN METH = MF/10 MITER = MF - 10*METH @@ -2306,7 +2123,7 @@ C ********************************************* 40 RH = DMAX1(RH,HMIN/DABS(H)) 50 RH = DMIN1(RH,HMAX/DABS(H),RMAX) - CALL RSCALE(N,L,RH,Y) + CALL I_RSCALE(N,L,RH,Y) RMAX = 10.0D+0 JCHANG = 1 H = H*RH @@ -2323,7 +2140,7 @@ END IF IDOUB = L + 1 - CALL CPYARY(N*L,Y,YHOLD) + CALL I_CPYARY(N*L,Y,YHOLD) 60 IF (DABS(RC-ONE).GT.UPBND) IWEVAL = MITER HUSED = H @@ -2348,7 +2165,7 @@ IF (JCHANG.EQ.1) THEN C IF WE HAVE CHANGED STEPSIZE THEN PREDICT A VALUE FOR Y(T+H) C AND EVALUATE THE DERIVATIVE THERE (STORED IN SAVE2()) - CALL PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) + CALL I_PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) IF(IERR.NE.0) GOTO 8000 DO 95 I=1,N YPRIME(I)=(Y(I,1)-ARH(I))/QI @@ -2371,7 +2188,7 @@ C ------------------------------------------------------------------- C IF INDICATED, THE MATRIX P = I/(H*EL(2)) - J IS RE-EVALUATED BEFORE C STARTING THE CORRECTOR ITERATION. IWEVAL IS SET = 0 TO INDICATE -C THAT THIS HAS BEEN DONE. P IS COMPUTED AND PROCESSED IN PSET. +C THAT THIS HAS BEEN DONE. P IS COMPUTED AND PROCESSED IN I_PSET. C THE PROCESSED MATRIX IS STORED IN PW C ------------------------------------------------------------------- IWEVAL = 0 @@ -2436,14 +2253,14 @@ JSNOLD = 0 MQ1TMP = MEQC1 MQ2TMP = MEQC2 - CALL PSET(Y,YPRIME,N,H,T,UROUND,EPSJAC,QI,MITER,MBND, + CALL I_PSET(Y,YPRIME,N,H,T,UROUND,EPSJAC,QI,MITER,MBND, + NIND1,NIND2,NIND3,IER,PDERV,RESID,NRENEW,YMAX,SAVE1,SAVE2, + SCALE,PW,PWCOPY,ERROR,IPIV,ITOL,RTOL,ATOL,NPSET,NJE,NRE,NDEC + ,IPAR,RPAR,IERR) IF(IERR.NE.0) GOTO 8000 QQQ=QI C -C NOTE THAT ERROR() IS JUST BEING USED AS A WORKSPACE BY PSET +C NOTE THAT ERROR() IS JUST BEING USED AS A WORKSPACE BY I_PSET IF (IER.NE.0) THEN C IF IER>0 THEN WE HAVE HAD A SINGULARITY IN THE ITERATION MATRIX IJUS=1 @@ -2467,14 +2284,14 @@ C LOOP. THE UPDATED Y VECTOR IS STORED TEMPORARILY IN SAVE1. C ********************************************************************** IF (.NOT.SAMPLE) THEN - CALL ITRAT2(QQQ,Y,YPRIME,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1, + CALL I_ITRAT2(QQQ,Y,YPRIME,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1, + WORKED,YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND, + NIND1,NIND2,NIND3,IPIV,1,ITOL,RTOL,ATOL,IPAR,RPAR, + HUSED,NBSOL,NRE,NQUSED,resid,IERR) IF(IERR.NE.0) GOTO 8000 ELSE - CALL ITRAT2(QQQ,Y,YPRIME,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1, + CALL I_ITRAT2(QQQ,Y,YPRIME,N,T,QI,BND,ARH,CRATE1,TCRAT1,M1, + WORKED,YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND, + NIND1,NIND2,NIND3,IPIV,0,ITOL,RTOL,ATOL,IPAR,RPAR, + HUSED,NBSOL,NRE,NQUSED,resid,IERR) @@ -2589,7 +2406,7 @@ ARH(I) = ARH(I) + EL(JP1)*Y(I,J1) 200 CONTINUE 210 CONTINUE - CALL PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) + CALL I_PRDICT(T,H,Y,L,N,IPAR,RPAR,IERR) IF(IERR.NE.0) GOTO 8000 DO 215 I=1,N YPRIME(I)=(Y(I,1)-ARH(I))/QQQ @@ -2603,7 +2420,7 @@ C FOR NOW WILL ASSUME THAT WE DO NOT WISH TO SAMPLE C AT THE N+2 STEP POINT C - CALL ITRAT2(QQQ,Y,YPRIME,N,T,QI,BND,ARH,CRATE2,TCRAT2,M2, + CALL I_ITRAT2(QQQ,Y,YPRIME,N,T,QI,BND,ARH,CRATE2,TCRAT2,M2, + WORKED,YMAX,ERROR,SAVE1,SAVE2,SCALE,PW,MF,MBND, + NIND1,NIND2,NIND3,IPIV,1,ITOL,RTOL,ATOL,IPAR,RPAR, + HUSED,NBSOL,NRE,NQUSED,resid,IERR) @@ -2661,10 +2478,10 @@ NRE=NRE+1 C IF (MF.GE. 23) THEN - CALL DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) + CALL I_DGBSL(PW,MBND(4),N,MBND(1),MBND(2),IPIV,SAVE1,0) NBSOL=NBSOL+1 ELSE - CALL SOL(N,N,PW,SAVE1,IPIV) + CALL I_SOL(N,N,PW,SAVE1,IPIV) NBSOL = NBSOL + 1 ENDIF DO 321 I=1,N @@ -2758,7 +2575,7 @@ IF(NQ.GT.1) FFAIL = 0.5D+0/DBLE(FLOAT(NQ)) IF(NQ.GT.2) FRFAIL = 0.5D+0/DBLE(FLOAT(NQ-1)) EFAIL = 0.5D+0/DBLE(FLOAT(L)) - CALL CPYARY(N*L,YHOLD,Y) + CALL I_CPYARY(N*L,YHOLD,Y) RMAX = 2.0D+0 IF (DABS(H).LE.HMIN*1.00001D+0) THEN C @@ -2787,10 +2604,10 @@ NQ=NEWQ RH=ONE/(PLFAIL*DBLE(FLOAT(-KFAIL))) L=NQ+1 - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL I_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) RC=RC*EL(1)/OLDLO OLDLO=EL(1) - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL I_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) ELSE NEWQ = NQ RH = ONE/ (PRFAIL*DBLE(FLOAT(-KFAIL))) @@ -2816,7 +2633,7 @@ C ********************************* JCHANG = 1 RH = DMAX1(HMIN/DABS(H),0.1D+0) - CALL HCHOSE(RH,H,OVRIDE) + CALL I_HCHOSE(RH,H,OVRIDE) H = H*RH DO 350 I = 1,N Y(I,1) = YHOLD(I,1) @@ -2832,11 +2649,11 @@ NQ = 1 L = 2 C RESET ORDER, RECALCULATE ERROR BOUNDS - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL I_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) LMAX = MAXDER + 1 RC = RC*EL(1)/OLDLO OLDLO = EL(1) - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL I_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) C NOW JUMP TO NORMAL CONTINUATION POINT GO TO 60 C ********************************************************************** @@ -3003,7 +2820,7 @@ GOTO 440 ENDIF RH = DMIN1(RH,RMAX) - CALL HCHOSE(RH,H,OVRIDE) + CALL I_HCHOSE(RH,H,OVRIDE) IF ((JSINUP.LE.20).AND.(KFLAG.EQ.0).AND.(RH.LT.1.1D+0)) THEN C WE HAVE RUN INTO PROBLEMS IDOUB = 10 @@ -3031,16 +2848,16 @@ NQ = NEWQ L = NQ + 1 C RESET ORDER,RECALCULATE ERROR BOUNDS - CALL COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) + CALL I_COSET(NQ,EL,ELST,TQ,NCOSET,MAXORD) LMAX = MAXDER + 1 RC = RC*EL(1)/OLDLO OLDLO = EL(1) - CALL ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) + CALL I_ERRORS(N,TQ,EDN,E,EUP,BND,EDDN) END IF RH = DMAX1(RH,HMIN/DABS(H)) RH = DMIN1(RH,HMAX/DABS(H),RMAX) - CALL RSCALE(N,L,RH,Y) + CALL I_RSCALE(N,L,RH,Y) RMAX = 10.0D+0 JCHANG = 1 H = H*RH @@ -3057,7 +2874,7 @@ C INFORMATION NECESSARY TO PERFORM AN INTERPOLATION TO FIND THE C SOLUTION AT THE SPECIFIED OUTPUT POINT IF APPROPRIATE. C ---------------------------------------------------------------------- - CALL CPYARY(N*L,Y,YHOLD) + CALL I_CPYARY(N*L,Y,YHOLD) NSTEP = NSTEP + 1 JSINUP = JSINUP + 1 JSNOLD = JSNOLD + 1 @@ -3112,7 +2929,7 @@ IF ((T-TOUT)*H.GE.0.0D+0) THEN C HAVE OVERSHOT TOUT WRITE (LOUT,*) T,TOUT,H - CALL INTERP(N,JSTART,H,T,Y,TOUT,Y0) + CALL I_INTERP(N,JSTART,H,T,Y,TOUT,Y0) HO = H T0 = TOUT IDID = -5 @@ -3123,7 +2940,7 @@ goto 30 endif c - IF(IJUS.EQ.0) CALL HCHOSE(RH,H,OVRIDE) + IF(IJUS.EQ.0) CALL I_HCHOSE(RH,H,OVRIDE) IF(.NOT.FINISH) THEN GO TO 40 ELSE @@ -3132,9 +2949,9 @@ 9000 FORMAT (1X,' CORRECTOR HAS NOT CONVERGED') END -C ------------------- END OF SUBROUTINE STIFF -------------------------- +C ------------------- END OF SUBROUTINE I_STIFF -------------------------- - SUBROUTINE RSCALE(N,L,RH,Y) + SUBROUTINE I_RSCALE(N,L,RH,Y) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C .. SCALAR ARGUMENTS .. @@ -3246,7 +3063,7 @@ END C--------------------------------------------------------------------------- - SUBROUTINE CPYARY(NELEM,SOURCE,TARGET) + SUBROUTINE I_CPYARY(NELEM,SOURCE,TARGET) IMPLICIT DOUBLE PRECISION(A-H,O-Z) C C COPIES THE ARRAY SOURCE() INTO THE ARRAY TARGET() @@ -3271,7 +3088,7 @@ END C---------------------------------------------------------------------------- - SUBROUTINE HCHOSE(RH,H,OVRIDE) + SUBROUTINE I_HCHOSE(RH,H,OVRIDE) IMPLICIT DOUBLE PRECISION(A-H,O-Z) COMMON / STPSZE / HSTPSZ(2,14) LOGICAL OVRIDE @@ -3306,953 +3123,3 @@ RETURN END -C -C ************************************************************ -C - DOUBLE PRECISION FUNCTION DLAMCH( CMACH ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - CHARACTER CMACH -* .. -* -* Purpose -* ======= -* -* DLAMCH determines double precision machine parameters. -* -* Arguments -* ========= -* -* CMACH (input) CHARACTER*1 -* Specifies the value to be returned by DLAMCH: -* = 'E' or 'e', DLAMCH := eps -* = 'S' or 's , DLAMCH := sfmin -* = 'B' or 'b', DLAMCH := base -* = 'P' or 'p', DLAMCH := eps*base -* = 'N' or 'n', DLAMCH := t -* = 'R' or 'r', DLAMCH := rnd -* = 'M' or 'm', DLAMCH := emin -* = 'U' or 'u', DLAMCH := rmin -* = 'L' or 'l', DLAMCH := emax -* = 'O' or 'o', DLAMCH := rmax -* -* where -* -* eps = relative machine precision -* sfmin = safe minimum, such that 1/sfmin does not overflow -* base = base of the machine -* prec = eps*base -* t = number of (base) digits in the mantissa -* rnd = 1.0 when rounding occurs in addition, 0.0 otherwise -* emin = minimum exponent before (gradual) underflow -* rmin = underflow threshold - base**(emin-1) -* emax = largest exponent before overflow -* rmax = overflow threshold - (base**emax)*(1-eps) -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE PRECISION ONE, ZERO - PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) -* .. -* .. Local Scalars .. - LOGICAL FIRST, LRND - INTEGER BETA, IMAX, IMIN, IT - DOUBLE PRECISION BASE, EMAX, EMIN, EPS, PREC, RMACH, RMAX, RMIN, - $ RND, SFMIN, SMALL, T -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL DLAMC2 -* .. -* .. Save statement .. - SAVE FIRST, EPS, SFMIN, BASE, T, RND, EMIN, RMIN, - $ EMAX, RMAX, PREC -* .. -* .. Data statements .. - DATA FIRST / .TRUE. / -* .. -* .. Executable Statements .. -* - IF( FIRST ) THEN - FIRST = .FALSE. - CALL DLAMC2( BETA, IT, LRND, EPS, IMIN, RMIN, IMAX, RMAX ) - BASE = BETA - T = IT - IF( LRND ) THEN - RND = ONE - EPS = ( BASE**( 1-IT ) ) / 2 - ELSE - RND = ZERO - EPS = BASE**( 1-IT ) - END IF - PREC = EPS*BASE - EMIN = IMIN - EMAX = IMAX - SFMIN = RMIN - SMALL = ONE / RMAX - IF( SMALL.GE.SFMIN ) THEN -* -* Use SMALL plus a bit, to avoid the possibility of rounding -* causing overflow when computing 1/sfmin. -* - SFMIN = SMALL*( ONE+EPS ) - END IF - END IF -* - IF( LSAME( CMACH, 'E' ) ) THEN - RMACH = EPS - ELSE IF( LSAME( CMACH, 'S' ) ) THEN - RMACH = SFMIN - ELSE IF( LSAME( CMACH, 'B' ) ) THEN - RMACH = BASE - ELSE IF( LSAME( CMACH, 'P' ) ) THEN - RMACH = PREC - ELSE IF( LSAME( CMACH, 'N' ) ) THEN - RMACH = T - ELSE IF( LSAME( CMACH, 'R' ) ) THEN - RMACH = RND - ELSE IF( LSAME( CMACH, 'M' ) ) THEN - RMACH = EMIN - ELSE IF( LSAME( CMACH, 'U' ) ) THEN - RMACH = RMIN - ELSE IF( LSAME( CMACH, 'L' ) ) THEN - RMACH = EMAX - ELSE IF( LSAME( CMACH, 'O' ) ) THEN - RMACH = RMAX - END IF -* - DLAMCH = RMACH - RETURN -* -* End of DLAMCH -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC1( BETA, T, RND, IEEE1 ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - LOGICAL IEEE1, RND - INTEGER BETA, T -* .. -* -* Purpose -* ======= -* -* DLAMC1 determines the machine parameters given by BETA, T, RND, and -* IEEE1. -* -* Arguments -* ========= -* -* BETA (output) INTEGER -* The base of the machine. -* -* T (output) INTEGER -* The number of ( BETA ) digits in the mantissa. -* -* RND (output) LOGICAL -* Specifies whether proper rounding ( RND = .TRUE. ) or -* chopping ( RND = .FALSE. ) occurs in addition. This may not -* be a reliable guide to the way in which the machine performs -* its arithmetic. -* -* IEEE1 (output) LOGICAL -* Specifies whether rounding appears to be done in the IEEE -* 'round to nearest' style. -* -* Further Details -* =============== -* -* The routine is based on the routine ENVRON by Malcolm and -* incorporates suggestions by Gentleman and Marovich. See -* -* Malcolm M. A. (1972) Algorithms to reveal properties of -* floating-point arithmetic. Comms. of the ACM, 15, 949-951. -* -* Gentleman W. M. and Marovich S. B. (1974) More on algorithms -* that reveal properties of floating point arithmetic units. -* Comms. of the ACM, 17, 276-277. -* -* ===================================================================== -* -* .. Local Scalars .. - LOGICAL FIRST, LIEEE1, LRND - INTEGER LBETA, LT - DOUBLE PRECISION A, B, C, F, ONE, QTR, SAVEC, T1, T2 -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. Save statement .. - SAVE FIRST, LIEEE1, LBETA, LRND, LT -* .. -* .. Data statements .. - DATA FIRST / .TRUE. / -* .. -* .. Executable Statements .. -* - IF( FIRST ) THEN - FIRST = .FALSE. - ONE = 1 -* -* LBETA, LIEEE1, LT and LRND are the local values of BETA, -* IEEE1, T and RND. -* -* Throughout this routine we use the function DLAMC3 to ensure -* that relevant values are stored and not held in registers, or -* are not affected by optimizers. -* -* Compute a = 2.0**m with the smallest positive integer m such -* that -* -* fl( a + 1.0 ) = a. -* - A = 1 - C = 1 -* -*+ WHILE( C.EQ.ONE )LOOP - 10 CONTINUE - IF( C.EQ.ONE ) THEN - A = 2*A - C = DLAMC3( A, ONE ) - C = DLAMC3( C, -A ) - GO TO 10 - END IF -*+ END WHILE -* -* Now compute b = 2.0**m with the smallest positive integer m -* such that -* -* fl( a + b ) .gt. a. -* - B = 1 - C = DLAMC3( A, B ) -* -*+ WHILE( C.EQ.A )LOOP - 20 CONTINUE - IF( C.EQ.A ) THEN - B = 2*B - C = DLAMC3( A, B ) - GO TO 20 - END IF -*+ END WHILE -* -* Now compute the base. a and c are neighbouring floating point -* numbers in the interval ( beta**t, beta**( t + 1 ) ) and so -* their difference is beta. Adding 0.25 to c is to ensure that it -* is truncated to beta and not ( beta - 1 ). -* - QTR = ONE / 4 - SAVEC = C - C = DLAMC3( C, -A ) - LBETA = C + QTR -* -* Now determine whether rounding or chopping occurs, by adding a -* bit less than beta/2 and a bit more than beta/2 to a. -* - B = LBETA - F = DLAMC3( B / 2, -B / 100 ) - C = DLAMC3( F, A ) - IF( C.EQ.A ) THEN - LRND = .TRUE. - ELSE - LRND = .FALSE. - END IF - F = DLAMC3( B / 2, B / 100 ) - C = DLAMC3( F, A ) - IF( ( LRND ) .AND. ( C.EQ.A ) ) - $ LRND = .FALSE. -* -* Try and decide whether rounding is done in the IEEE 'round to -* nearest' style. B/2 is half a unit in the last place of the two -* numbers A and SAVEC. Furthermore, A is even, i.e. has last bit -* zero, and SAVEC is odd. Thus adding B/2 to A should not change -* A, but adding B/2 to SAVEC should change SAVEC. -* - T1 = DLAMC3( B / 2, A ) - T2 = DLAMC3( B / 2, SAVEC ) - LIEEE1 = ( T1.EQ.A ) .AND. ( T2.GT.SAVEC ) .AND. LRND -* -* Now find the mantissa, t. It should be the integer part of -* log to the base beta of a, however it is safer to determine t -* by powering. So we find t as the smallest positive integer for -* which -* -* fl( beta**t + 1.0 ) = 1.0. -* - LT = 0 - A = 1 - C = 1 -* -*+ WHILE( C.EQ.ONE )LOOP - 30 CONTINUE - IF( C.EQ.ONE ) THEN - LT = LT + 1 - A = A*LBETA - C = DLAMC3( A, ONE ) - C = DLAMC3( C, -A ) - GO TO 30 - END IF -*+ END WHILE -* - END IF -* - BETA = LBETA - T = LT - RND = LRND - IEEE1 = LIEEE1 - RETURN -* -* End of DLAMC1 -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC2( BETA, T, RND, EPS, EMIN, RMIN, EMAX, RMAX ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - LOGICAL RND - INTEGER BETA, EMAX, EMIN, T - DOUBLE PRECISION EPS, RMAX, RMIN -* .. -* -* Purpose -* ======= -* -* DLAMC2 determines the machine parameters specified in its argument -* list. -* -* Arguments -* ========= -* -* BETA (output) INTEGER -* The base of the machine. -* -* T (output) INTEGER -* The number of ( BETA ) digits in the mantissa. -* -* RND (output) LOGICAL -* Specifies whether proper rounding ( RND = .TRUE. ) or -* chopping ( RND = .FALSE. ) occurs in addition. This may not -* be a reliable guide to the way in which the machine performs -* its arithmetic. -* -* EPS (output) DOUBLE PRECISION -* The smallest positive number such that -* -* fl( 1.0 - EPS ) .LT. 1.0, -* -* where fl denotes the computed value. -* -* EMIN (output) INTEGER -* The minimum exponent before (gradual) underflow occurs. -* -* RMIN (output) DOUBLE PRECISION -* The smallest normalized number for the machine, given by -* BASE**( EMIN - 1 ), where BASE is the floating point value -* of BETA. -* -* EMAX (output) INTEGER -* The maximum exponent before overflow occurs. -* -* RMAX (output) DOUBLE PRECISION -* The largest positive number for the machine, given by -* BASE**EMAX * ( 1 - EPS ), where BASE is the floating point -* value of BETA. -* -* Further Details -* =============== -* -* The computation of EPS is based on a routine PARANOIA by -* W. Kahan of the University of California at Berkeley. -* -* ===================================================================== -* -* .. Local Scalars .. - LOGICAL FIRST, IEEE, IWARN, LIEEE1, LRND - INTEGER GNMIN, GPMIN, I, LBETA, LEMAX, LEMIN, LT, - $ NGNMIN, NGPMIN - DOUBLE PRECISION A, B, C, HALF, LEPS, LRMAX, LRMIN, ONE, RBASE, - $ SIXTH, SMALL, THIRD, TWO, ZERO -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. External Subroutines .. - EXTERNAL DLAMC1, DLAMC4, DLAMC5 -* .. -* .. Intrinsic Functions .. - INTRINSIC ABS, MAX, MIN -* .. -* .. Save statement .. - SAVE FIRST, IWARN, LBETA, LEMAX, LEMIN, LEPS, LRMAX, - $ LRMIN, LT -* .. -* .. Data statements .. - DATA FIRST / .TRUE. / , IWARN / .FALSE. / -* .. -* .. Executable Statements .. -* - IF( FIRST ) THEN - FIRST = .FALSE. - ZERO = 0 - ONE = 1 - TWO = 2 -* -* LBETA, LT, LRND, LEPS, LEMIN and LRMIN are the local values of -* BETA, T, RND, EPS, EMIN and RMIN. -* -* Throughout this routine we use the function DLAMC3 to ensure -* that relevant values are stored and not held in registers, or -* are not affected by optimizers. -* -* DLAMC1 returns the parameters LBETA, LT, LRND and LIEEE1. -* - CALL DLAMC1( LBETA, LT, LRND, LIEEE1 ) -* -* Start to find EPS. -* - B = LBETA - A = B**( -LT ) - LEPS = A -* -* Try some tricks to see whether or not this is the correct EPS. -* - B = TWO / 3 - HALF = ONE / 2 - SIXTH = DLAMC3( B, -HALF ) - THIRD = DLAMC3( SIXTH, SIXTH ) - B = DLAMC3( THIRD, -HALF ) - B = DLAMC3( B, SIXTH ) - B = ABS( B ) - IF( B.LT.LEPS ) - $ B = LEPS -* - LEPS = 1 -* -*+ WHILE( ( LEPS.GT.B ).AND.( B.GT.ZERO ) )LOOP - 10 CONTINUE - IF( ( LEPS.GT.B ) .AND. ( B.GT.ZERO ) ) THEN - LEPS = B - C = DLAMC3( HALF*LEPS, ( TWO**5 )*( LEPS**2 ) ) - C = DLAMC3( HALF, -C ) - B = DLAMC3( HALF, C ) - C = DLAMC3( HALF, -B ) - B = DLAMC3( HALF, C ) - GO TO 10 - END IF -*+ END WHILE -* - IF( A.LT.LEPS ) - $ LEPS = A -* -* Computation of EPS complete. -* -* Now find EMIN. Let A = + or - 1, and + or - (1 + BASE**(-3)). -* Keep dividing A by BETA until (gradual) underflow occurs. This -* is detected when we cannot recover the previous A. -* - RBASE = ONE / LBETA - SMALL = ONE - DO 20 I = 1, 3 - SMALL = DLAMC3( SMALL*RBASE, ZERO ) - 20 CONTINUE - A = DLAMC3( ONE, SMALL ) - CALL DLAMC4( NGPMIN, ONE, LBETA ) - CALL DLAMC4( NGNMIN, -ONE, LBETA ) - CALL DLAMC4( GPMIN, A, LBETA ) - CALL DLAMC4( GNMIN, -A, LBETA ) - IEEE = .FALSE. -* - IF( ( NGPMIN.EQ.NGNMIN ) .AND. ( GPMIN.EQ.GNMIN ) ) THEN - IF( NGPMIN.EQ.GPMIN ) THEN - LEMIN = NGPMIN -* ( Non twos-complement machines, no gradual underflow; -* e.g., VAX ) - ELSE IF( ( GPMIN-NGPMIN ).EQ.3 ) THEN - LEMIN = NGPMIN - 1 + LT - IEEE = .TRUE. -* ( Non twos-complement machines, with gradual underflow; -* e.g., IEEE standard followers ) - ELSE - LEMIN = MIN( NGPMIN, GPMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -* - ELSE IF( ( NGPMIN.EQ.GPMIN ) .AND. ( NGNMIN.EQ.GNMIN ) ) THEN - IF( ABS( NGPMIN-NGNMIN ).EQ.1 ) THEN - LEMIN = MAX( NGPMIN, NGNMIN ) -* ( Twos-complement machines, no gradual underflow; -* e.g., CYBER 205 ) - ELSE - LEMIN = MIN( NGPMIN, NGNMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -* - ELSE IF( ( ABS( NGPMIN-NGNMIN ).EQ.1 ) .AND. - $ ( GPMIN.EQ.GNMIN ) ) THEN - IF( ( GPMIN-MIN( NGPMIN, NGNMIN ) ).EQ.3 ) THEN - LEMIN = MAX( NGPMIN, NGNMIN ) - 1 + LT -* ( Twos-complement machines with gradual underflow; -* no known machine ) - ELSE - LEMIN = MIN( NGPMIN, NGNMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -* - ELSE - LEMIN = MIN( NGPMIN, NGNMIN, GPMIN, GNMIN ) -* ( A guess; no known machine ) - IWARN = .TRUE. - END IF -*** -* Comment out this if block if EMIN is ok - IF( IWARN ) THEN - FIRST = .TRUE. - WRITE( 6, FMT = 9999 )LEMIN - END IF -*** -* -* Assume IEEE arithmetic if we found denormalised numbers above, -* or if arithmetic seems to round in the IEEE style, determined -* in routine DLAMC1. A true IEEE machine should have both things -* true; however, faulty machines may have one or the other. -* - IEEE = IEEE .OR. LIEEE1 -* -* Compute RMIN by successive division by BETA. We could compute -* RMIN as BASE**( EMIN - 1 ), but some machines underflow during -* this computation. -* - LRMIN = 1 - DO 30 I = 1, 1 - LEMIN - LRMIN = DLAMC3( LRMIN*RBASE, ZERO ) - 30 CONTINUE -* -* Finally, call DLAMC5 to compute EMAX and RMAX. -* - CALL DLAMC5( LBETA, LT, LEMIN, IEEE, LEMAX, LRMAX ) - END IF -* - BETA = LBETA - T = LT - RND = LRND - EPS = LEPS - EMIN = LEMIN - RMIN = LRMIN - EMAX = LEMAX - RMAX = LRMAX -* - RETURN -* - 9999 FORMAT( / / ' WARNING. The value EMIN may be incorrect:-', - $ ' EMIN = ', I8, / - $ ' If, after inspection, the value EMIN looks', - $ ' acceptable please comment out ', - $ / ' the IF block as marked within the code of routine', - $ ' DLAMC2,', / ' otherwise supply EMIN explicitly.', / ) -* -* End of DLAMC2 -* - END -* -************************************************************************ -* - DOUBLE PRECISION FUNCTION DLAMC3( A, B ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - DOUBLE PRECISION A, B -* .. -* -* Purpose -* ======= -* -* DLAMC3 is intended to force A and B to be stored prior to doing -* the addition of A and B , for use in situations where optimizers -* might hold one of these in a register. -* -* Arguments -* ========= -* -* A, B (input) DOUBLE PRECISION -* The values A and B. -* -* ===================================================================== -* -* .. Executable Statements .. -* - DLAMC3 = A + B -* - RETURN -* -* End of DLAMC3 -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC4( EMIN, START, BASE ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - INTEGER BASE, EMIN - DOUBLE PRECISION START -* .. -* -* Purpose -* ======= -* -* DLAMC4 is a service routine for DLAMC2. -* -* Arguments -* ========= -* -* EMIN (output) EMIN -* The minimum exponent before (gradual) underflow, computed by -* setting A = START and dividing by BASE until the previous A -* can not be recovered. -* -* START (input) DOUBLE PRECISION -* The starting point for determining EMIN. -* -* BASE (input) INTEGER -* The base of the machine. -* -* ===================================================================== -* -* .. Local Scalars .. - INTEGER I - DOUBLE PRECISION A, B1, B2, C1, C2, D1, D2, ONE, RBASE, ZERO -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. Executable Statements .. -* - A = START - ONE = 1 - RBASE = ONE / BASE - ZERO = 0 - EMIN = 1 - B1 = DLAMC3( A*RBASE, ZERO ) - C1 = A - C2 = A - D1 = A - D2 = A -*+ WHILE( ( C1.EQ.A ).AND.( C2.EQ.A ).AND. -* $ ( D1.EQ.A ).AND.( D2.EQ.A ) )LOOP - 10 CONTINUE - IF( ( C1.EQ.A ) .AND. ( C2.EQ.A ) .AND. ( D1.EQ.A ) .AND. - $ ( D2.EQ.A ) ) THEN - EMIN = EMIN - 1 - A = B1 - B1 = DLAMC3( A / BASE, ZERO ) - C1 = DLAMC3( B1*BASE, ZERO ) - D1 = ZERO - DO 20 I = 1, BASE - D1 = D1 + B1 - 20 CONTINUE - B2 = DLAMC3( A*RBASE, ZERO ) - C2 = DLAMC3( B2 / RBASE, ZERO ) - D2 = ZERO - DO 30 I = 1, BASE - D2 = D2 + B2 - 30 CONTINUE - GO TO 10 - END IF -*+ END WHILE -* - RETURN -* -* End of DLAMC4 -* - END -* -************************************************************************ -* - SUBROUTINE DLAMC5( BETA, P, EMIN, IEEE, EMAX, RMAX ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* October 31, 1992 -* -* .. Scalar Arguments .. - LOGICAL IEEE - INTEGER BETA, EMAX, EMIN, P - DOUBLE PRECISION RMAX -* .. -* -* Purpose -* ======= -* -* DLAMC5 attempts to compute RMAX, the largest machine floating-point -* number, without overflow. It assumes that EMAX + abs(EMIN) sum -* approximately to a power of 2. It will fail on machines where this -* assumption does not hold, for example, the Cyber 205 (EMIN = -28625, -* EMAX = 28718). It will also fail if the value supplied for EMIN is -* too large (i.e. too close to zero), probably with overflow. -* -* Arguments -* ========= -* -* BETA (input) INTEGER -* The base of floating-point arithmetic. -* -* P (input) INTEGER -* The number of base BETA digits in the mantissa of a -* floating-point value. -* -* EMIN (input) INTEGER -* The minimum exponent before (gradual) underflow. -* -* IEEE (input) LOGICAL -* A logical flag specifying whether or not the arithmetic -* system is thought to comply with the IEEE standard. -* -* EMAX (output) INTEGER -* The largest exponent before overflow -* -* RMAX (output) DOUBLE PRECISION -* The largest machine floating-point number. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE PRECISION ZERO, ONE - PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 ) -* .. -* .. Local Scalars .. - INTEGER EXBITS, EXPSUM, I, LEXP, NBITS, TRY, UEXP - DOUBLE PRECISION OLDY, RECBAS, Y, Z -* .. -* .. External Functions .. - DOUBLE PRECISION DLAMC3 - EXTERNAL DLAMC3 -* .. -* .. Intrinsic Functions .. - INTRINSIC MOD -* .. -* .. Executable Statements .. -* -* First compute LEXP and UEXP, two powers of 2 that bound -* abs(EMIN). We then assume that EMAX + abs(EMIN) will sum -* approximately to the bound that is closest to abs(EMIN). -* (EMAX is the exponent of the required number RMAX). -* - LEXP = 1 - EXBITS = 1 - 10 CONTINUE - TRY = LEXP*2 - IF( TRY.LE.( -EMIN ) ) THEN - LEXP = TRY - EXBITS = EXBITS + 1 - GO TO 10 - END IF - IF( LEXP.EQ.-EMIN ) THEN - UEXP = LEXP - ELSE - UEXP = TRY - EXBITS = EXBITS + 1 - END IF -* -* Now -LEXP is less than or equal to EMIN, and -UEXP is greater -* than or equal to EMIN. EXBITS is the number of bits needed to -* store the exponent. -* - IF( ( UEXP+EMIN ).GT.( -LEXP-EMIN ) ) THEN - EXPSUM = 2*LEXP - ELSE - EXPSUM = 2*UEXP - END IF -* -* EXPSUM is the exponent range, approximately equal to -* EMAX - EMIN + 1 . -* - EMAX = EXPSUM + EMIN - 1 - NBITS = 1 + EXBITS + P -* -* NBITS is the total number of bits needed to store a -* floating-point number. -* - IF( ( MOD( NBITS, 2 ).EQ.1 ) .AND. ( BETA.EQ.2 ) ) THEN -* -* Either there are an odd number of bits used to store a -* floating-point number, which is unlikely, or some bits are -* not used in the representation of numbers, which is possible, -* (e.g. Cray machines) or the mantissa has an implicit bit, -* (e.g. IEEE machines, Dec Vax machines), which is perhaps the -* most likely. We have to assume the last alternative. -* If this is true, then we need to reduce EMAX by one because -* there must be some way of representing zero in an implicit-bit -* system. On machines like Cray, we are reducing EMAX by one -* unnecessarily. -* - EMAX = EMAX - 1 - END IF -* - IF( IEEE ) THEN -* -* Assume we are on an IEEE machine which reserves one exponent -* for infinity and NaN. -* - EMAX = EMAX - 1 - END IF -* -* Now create RMAX, the largest machine number, which should -* be equal to (1.0 - BETA**(-P)) * BETA**EMAX . -* -* First compute 1.0 - BETA**(-P), being careful that the -* result is less than 1.0 . -* - RECBAS = ONE / BETA - Z = BETA - ONE - Y = ZERO - DO 20 I = 1, P - Z = Z*RECBAS - IF( Y.LT.ONE ) - $ OLDY = Y - Y = DLAMC3( Y, Z ) - 20 CONTINUE - IF( Y.GE.ONE ) - $ Y = OLDY -* -* Now multiply by BETA**EMAX to get RMAX. -* - DO 30 I = 1, EMAX - Y = DLAMC3( Y*BETA, ZERO ) - 30 CONTINUE -* - RMAX = Y - RETURN -* -* End of DLAMC5 -* - END - LOGICAL FUNCTION LSAME( CA, CB ) -* -* -- LAPACK auxiliary routine (version 2.0) -- -* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., -* Courant Institute, Argonne National Lab, and Rice University -* September 30, 1994 -* -* .. Scalar Arguments .. - CHARACTER CA, CB -* .. -* -* Purpose -* ======= -* -* LSAME returns .TRUE. if CA is the same letter as CB regardless of -* case. -* -* Arguments -* ========= -* -* CA (input) CHARACTER*1 -* CB (input) CHARACTER*1 -* CA and CB specify the single characters to be compared. -* -* ===================================================================== -* -* .. Intrinsic Functions .. - INTRINSIC ICHAR -* .. -* .. Local Scalars .. - INTEGER INTA, INTB, ZCODE -* .. -* .. Executable Statements .. -* -* Test if the characters are equal -* - LSAME = CA.EQ.CB - IF( LSAME ) - $ RETURN -* -* Now test for equivalence if both characters are alphabetic. -* - ZCODE = ICHAR( 'Z' ) -* -* Use 'Z' rather than 'A' so that ASCII can be detected on Prime -* machines, on which ICHAR returns a value with bit 8 set. -* ICHAR('A') on Prime machines returns 193 which is the same as -* ICHAR('A') on an EBCDIC machine. -* - INTA = ICHAR( CA ) - INTB = ICHAR( CB ) -* - IF( ZCODE.EQ.90 .OR. ZCODE.EQ.122 ) THEN -* -* ASCII is assumed - ZCODE is the ASCII code of either lower or -* upper case 'Z'. -* - IF( INTA.GE.97 .AND. INTA.LE.122 ) INTA = INTA - 32 - IF( INTB.GE.97 .AND. INTB.LE.122 ) INTB = INTB - 32 -* - ELSE IF( ZCODE.EQ.233 .OR. ZCODE.EQ.169 ) THEN -* -* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or -* upper case 'Z'. -* - IF( INTA.GE.129 .AND. INTA.LE.137 .OR. - $ INTA.GE.145 .AND. INTA.LE.153 .OR. - $ INTA.GE.162 .AND. INTA.LE.169 ) INTA = INTA + 64 - IF( INTB.GE.129 .AND. INTB.LE.137 .OR. - $ INTB.GE.145 .AND. INTB.LE.153 .OR. - $ INTB.GE.162 .AND. INTB.LE.169 ) INTB = INTB + 64 -* - ELSE IF( ZCODE.EQ.218 .OR. ZCODE.EQ.250 ) THEN -* -* ASCII is assumed, on Prime machines - ZCODE is the ASCII code -* plus 128 of either lower or upper case 'Z'. -* - IF( INTA.GE.225 .AND. INTA.LE.250 ) INTA = INTA - 32 - IF( INTB.GE.225 .AND. INTB.LE.250 ) INTB = INTB - 32 - END IF - LSAME = INTA.EQ.INTB -* -* RETURN -* -* End of LSAME -* - END - -C---------------------------------------------------------------------------- - odepkg/src/cash.tgz0000644000176000010400000021024110744424316015446 0ustar marcoAdministrators‹%;dGä[[sÛF–ös~EÏSH‚DJ²ã¤Tµ Ñ$aã dæ–(‰ %jHÊŽÿý|çt7иPñÔN¶vk‘X¢ûô¹_[׋Ýýñ«¿÷9Áóîü\}[ý®ŸW½“w§½“Óó³Óþ«“^ÿ¼wöJœÿÍxñó¼Û/¶B¼Êï7‹ÝáuõÞb¾ÿy®IþËÏ7·7‹¥{û·œAüx{vÖ.ÿ³ÞÛÞY¿&ÿ³³~ÿ•øaâÿwù‹|"Å0ñ¥ˆäÀùžñ,’i0ôÂp.²$¼”™ðDgšdY0 ò`4êþp-²y–ËH$#1 Ò,'©/S‘¤~{é\øX&Sç ùëÌ˃$Î6&)†A,½ð‚hà 8û‡k¼nž¾mWw÷{ÑvEÊ">,ooEêŠ!ÔUt~wImÿkõð´Ü®kwqí>ÿAáÿü~µOÛÍÝvñ ðãív¹»Ííþëb»üE|Û<‹ëÅ£Ø.oV»ývõùy¿«½X<Þo¶Øÿ°¹YÝ~£žo–[±¿_Šýrû°›[þeÏÄxù¸Ü.Öbúüy½ºáêzù¸[b÷gÓg»ûåøü7ŒƒLc FÀ]ìW›Ç_Är…÷[ñe¹ÝáwÑ}ˆ†èˆÍVt{B{+6O´­ \¿‰õb_ît™muÊKoÄê‘ÁÞož@Í=‚¾¯«õZ|^ŠçÝòöyíÖŠ« Ÿ$³\xñ\\yiêÅùü¬Ýßoðvùe© ÷냦íâqÿ ˆôf8Áo„A>'ìGAË,#úÔKó`8 ½TLg)TJºBdKBŠØw˜·â°6`àÍr¿X­wŠfýöF +Q>ޏ4œ&̘…#ðÜï÷O?ýúÕ½{|v7Û»ãµÚ´;^=ÞnŽÇÓðK³ yÏýþaÍÇÏ¡M;0f}#î_–Ъëåê ÐYˆk(ñ÷©ÌzóxÇ ÆÚR‚¿ˆÕ­xÜìñu»‚Žî7MeÂîR<^»Ž8ïaÑâñ5dží± F«[€­7›­#›Ýž–Gž'ý^ïä¨wzÒ#ùÏ2OóCüÀ_E6¤Ð˜ªrØÉOœIâÌOœ/œ\ƾœÀ|'¤O«$ýè¨ýoð þ¦¾FÚãeêÛ'8 'È“ÐIé‹Ç?AOœ_J0ÎÈ™bå%mt™¦]–ÀëÿÌó…DDCf{˜ \ÀWû-G½ò—O‹íþaù¸'õˆêx½ÓïíÕà×ëåÝRno ¹ÙÕ;Ñ÷~SŸÉÇ»53¢xŒs¼VnѼ$ÓX<Ê·â++,,ÿi½\ñ@·´æ²o¹Þ<z;êÝfsCFóyqóÐ ö6÷ðwŸ— “½æJÚ/þX’Ã1`à‚7âj±&®6XNH…ø°¸þçóž * }Þ«•ÞÃ+o.c½‚ÝÛXÑf±{¾»[îHíwH߯lo'E–öùùN-ÞÃvð„Øp½¹Yº6GÄWòÙ;ÍŠÍ ú–€–¹_íŸoŒ>¸ÿ;Uÿ Y\©¼ 2„[1 ²š_tæ^×™wúô基ü~‰»]ƒkì·¥9öY^8–ƒÔ †SI>º[œ­_Y^Y3' ~CÍ+Å¼Ñ kÊ@h]at†2+Vô`\N¸¼lâh¶ærœz†Óœ¶óÚ¢ Dâú®t3èiC”€þ@úB~¢Ø@™†o3†N± €”Iƒt©FS—yù$s9_Þ”x›!ú½wÄÛ³ó£·çïÑé½ÿé´ëj8}¦I“İ{~#tÅ€ìÅ*Ä©d˜…H¬ÐÒF,v#‘#QÊ'èã(=‰Âæ¨wþ“cÁNïûN§6NdKåp–fœ,[Ôéô9OHÄ"[¯‚VuBÖA˦)’1X¼{_`q,ލ8XS° Ü^î]$?®ÍœåÍ®+âÍv4Aôƒó¶¤¾9âéé¢=uÑžƒ$’/H¡ÿ$Ú1ËcdŒ)^«­[‡—J8šÊ^~Tšk!~›Ó'ù-Ð]Ü-Eÿí;·°«£ÿæSõˆkÃåJ5H' ³âJo8ð`¼VVr¤âÆSÃ,óY ÷>¢ºKåTz9É€ŒŠAriiõÆJZ”O #§y‘„à„°Å5b‰ùë…Z 5%o_‹ ‹í~×ÈO,UëS©Ï¡ªäI⼈RuGסþÀ Cui—B‚è5Nu’ØØÂ;±ªŠ ñ٥ٸúyMèsCŠ'.aA s"”ñö“Ê=5mÊjÞNQ™æÉ”¦t•Ì^.®&A©(Ð&_f° Ÿ©wë'Úþÿ*CDð4âÁ8YŒ'9~Èy£¡CëȘ¿AEBýXµ—"ãNßux‡£3 BÙhdÉ*9IÀ£Ð“ƒËÙ÷‘–D£‹~Ïé÷þ)µ"úg ½l&WÒw R&Y¯ÿ€¥´@G-ùئ&Ð{ƒ™rî±ÎQ&…+ofkÃdÀg’À ú0ÛlJÞøR†s—?>=1„«JŒ`• ºT%ÞïÀb§…xè@œ\@¢Ó 4-mdoRúì(ƒ`4·S.ÓD0Rˆ2‡O€¨Ld œ€6N­É “¦x§2Ï|>eq“N7”²Ç8R2šÕ̺Hµ£nl=±¶ÆIÞ¾²§JÙÐhÛ,”C&c♬ŸxÔûž „C'™ Þ‘ëÎd.bWª›WÏ^wÌªÒ »¤¤ 'Ð顜&^®ÁTAe4,˜ùÉ’¡wâÄ2^M½ŸÄ²Û8’Ï2(w¦qÇÒUæ0KÉ|DÓÛœ¶¡IœM“DSðRÌç`\mG‚L$¼QNšIÝU(Æð`ÒwÄ ò ÛÜ8=¶|S ¬†°W9;—t= 0˜eúe -ZFÉòzYµ†Ñ.¿ŒÔ•§ ¼±Eh6 ×3T†¤üu#/`“;N šÈÎYWR«i©†¤½â+äZÊ­s ]¢:³¥³/z¬Õ€ÛðUð*C”%Ùhª`l0¬°à¸ùdÖpä¬f„A±Þ§GdT‘ÍKD›OÕ·ì¼ùxc¡T!¸‡#>KiÜ…é‰sNtJúí P †®µ‡ “1göZfÔ[¥ò0¦Œ¢(i,"à VÞœº·s±D2ævÀïÒˆý2®8ÿfýŸ§Á'bT‚Q5\³ˆB€÷Æ ÂXƒ÷‰ ªb1²›b*ßfå>Å6 ¬î#Æ6û ¥8HŽq“ßõùݬõÝ©z'ÞoD¯uÑ-ê¿æ¼Ö,S=̘„j˜ý±>Ó|mØ‹‚¥ ð 1þ7™&†éÖ^ìúJ)p#Hð6½BŦ AßǼ‰œ³ -`5Äo‚®ôô &IzrøùäÐišÛf×l:­ì-x4ˆTh©8j{'•ˆÐÓ‡³CÅ)nï’TI?aŸ¯€|ÏÅ«7šz¨ÐA¾ª$WfÀIUÚj«ÂåDÆvÊOf­Ék–P¿)ÉJv¨F»I½O€è",Èô[«ՑÁB¯Âí–!wn% «P›S9L¢H%г8¤‘PÀaN"—Ò×I˜ÒLZ‘ÑfXCߊْ)À©8S…ÌÐˤ¡ó´nïLd“dú¤.தä ~Ý+xDSU¤Å&U…š‡Ê4Ň:qW]eõSžr³˜¸FÉ™9*-Ž¢~§GI¼†Œ5ÎP–u5õ‡”ñGx ᥽ŠP/´A¨ðXÀKP)E•×ܤ>—Ä•6mSïTqi° «ª{ j:ËΪÛeYf9Œ8o6°Ã„Â.£Á öMxÃ!wÆÓY?¨]Áš¨„plMÚ¢ìˆ2&ZÇG/¿î¶àFÌaûO`^‘Ä9NIUòÖbé•:—äâ²_Ó¼ÓA¶-¾àׯûÝ㸠^µ–@…9¢1â>rÙ ¸’TÖgÚ¾¢Y3IòÂ+oNF,àmRc§(RÊöEEô ‰F'ñQ,Çl :«Æ>J×8¥¢<'TY¼M’' ‘à2ð•ÂÌá:AWiùH•û8œ¸É~H›¸DÜ?²¸¯>Í‚js¨)Õød'£v®I)Ã+ÊC‘U{­yká¦GB%É0ÁÎÛº Ô#\Û”ÀÚ À3ŒÁ™Ò‰PÈ-€­‰y©#Tr{ Ö»‹“FÊ]}Ÿ6ÛEU驊µlÍê5ëÆEâSÄ 5ÅJakÔ™Rd7Ü—õ(EÖ`‘M½fŒWÝCè€qJÍÏT«Ã¡ ÀÛýfM†µø¼ë|c£y#ê³Ö(¡Nû nîƒK]óQ@ÉDGùîcöÚ uÛ) Þˆú?¨? öHû…ekË®\Çz¼â§vq»À„û'â‚Å¡™Ð ã´ CŧÃ0¡rVÙ\E¥"P9¯Â¨ Ò£]qtVn?“•HGþSaæ˜ú¹9ù䄵¨”‹06òcfz¦[P´Ó‘’P I׆eCÝt½3Õõå'òÒ9­6-(}‡¾ž «¹I ,ø‚ 6i®Ù9mör8:“ŠL‹DG–YœA¤™ dɼ¥/­Å}ë­ 9AÃylÑÜzZn-R¬) aJJËvØfɬ“X¿*•Èb7&§aEïRÚY¬gsx“_‘CµdÙ UÑÖR<¨Žu[«:?,Ƈ•éŸ5¸RjÎU“,‡•º“lº¢uÑN˜Š˜ŸtZÇ}”Rò o¢l;ô²Ü¡“VRA36jmÖ¹c‘ñYs;îËÖ†Zf 7‹ßáKÒÙ=¥‘qÑ›­ŽL.Dc\¢¹gÏK &³0Ï–ÝËÙHÙhæ:en)žŽT&~0O¢/”D 1½Ú/GÜ=aªÀêî Y ¯íeä¡®¥¨Y7F] SÖŠ²?Ö›`³!íšP^Sì­=WöNl†Zé«…e¿0Ý,‰JÛÕ¢nÞx¹ªfèš­ûƒy9B·P'"að³©2ÁõÔÊl‘…sÉMŠ‘ ¢B·=rÞpÎ Ö…J€±CÚŒ>ý7í 'Ôh±ñà$’™ç9¦k@/°ÜÞ[pÿ{YNù[¡ŒHU KÐ6ô¨My‹¥í°-Ø'–~Bw4躑ª{áÖYçÆpˆ!PIíœbæifÝʳšÙnPr˜ó.‰œN4ˆ×‡=tœÊïÔܵ!™åê:U¶9„–VÃ+ˆÈÓ¹rü•iŽeX¨;orä•F½¢(3yæÍEJ™[ÚÊÅ^R7ýj}V{ÎQÄ^:¨Ø¥3˳.nŽGȳó•jzŠÒ.ˆNY¡sCc–R»©{Ü;9éÚz=vTÙl4 øÒ‘Jõè°lê Ë[‚!Öî~}·q² ÀxgÈÉ÷映 }éÔœm‘^QjƒÜ›%ëV„僕âtÄ‘è [TÐËÜŽ¡ÊlZkR¹ V86QV~/÷ÌÁs•òqò-s¨«×¯iz\žj½ÍšmI­›e׆Õ0Ë’a`ùJÓJ-R!¨K~¦À#€Ôõ…。"%•Y1ùÒt×h2ÇOíÓMHWq‚£à Ë÷Cs3~ôHá¬ÏûÆùûrX¶‹pF/“HuÑ(º“¨ÎŠÛX»õ_æ¨û¥Å¥Vïõ'œ9Ðî [Ñ+⊾9ft\£mé#O˜3•Ã狦Ɍ¯ý™¾I›»JüÈ0ˆ‚¸2+ø,,Ài¤ÆUÂ@ןŸÜ`åqG6£[’ä<õåAH×#´áØy³øóé›#nv׋µ#V7‹‡ÅŸøõf³·½Ô ¶¬®Jgëþ4{¿#|«Ý é„^ªü=].Jc/,ÍŸÿÖ™;s?Éùo!ø¯"ˆS…R2bÈ"Yah]yIù…÷—©k 5 [°ðE¦…­®ê¾°—zŽä1°Ï#¨ŽhfOŒ-Q%Ù!"¦¾;‘$ÑVh©¿ŽËÙrûøÏzT±Â™Ž .¹HT†JWÞ¥š/Å@â _L‚3ƒ“úû;Æ‚-[´óÜ„ÁNù’E5˨=\è‰óëæŠ—ä©èÔï·ny3Îì%MHt詳‘KÈWõÍ›¥„õèÁšw>t[n Üx §+ÏmWªwþB¯[HñG .È•¶÷¾ IjÓYýþæáùMÏùdé[mYyÙ–Û/ŠrÁÔÿ¦‹`L9–‡ EѼ¸ª?<FÔÃf€ÀœÏ*@äeð^änÛ¶*¦eϹ#%#š^_œ]ó<·rÝ ¸_PD Õ»:ÁþÓ1*Uû€é¶hôKdÛÏ‹£¶v®´·“#a_ˆÛ®°/ñ[4æñ”ééêNg¤ÌðB¨_¢¨[¿q£–…C;9i n˜Ò¬ŒO?úð†/ @y?t/4•€V^S!Gê3‡‹†®G#2?ǯ_÷õßn2™µ¬çØæ'Æ}—¬}kš¬: ›å¾Æª®åv…[ÃÕܪ‡H'ó.e¿öaÁeÙUåûgÅnksÙÖ «äÚq_Õ¢zÃt†êVð‹Dÿ@ye²}’W> rÂЋ†“Îòi·Zo4ŠBÌÔîÙýs»7UO)¹ 7Dç‚«©>OM¸[U¶°*Ý*^®³’2×5£€_ùuçBÕfg ©{! HfçòžsÞW–ŒµK{`Ž÷±3Ô—(A¼­ ·4N íÅIßÌŽwõ& ’T éñDíÌ?Õ ñêÈØ,ïkê9|c;] (·÷Njû¤²F¥Á?Ö·RYbmíÕ¶æAĹ3UøVµd,Óäû ÕÔ ‡êY\•gõ[ÏâtQýÁ¿¾J¥.µ³JMZ¬@ÕºáY9–L·â‹OùÀæ=%­vš"Î.ʯ °,Ÿ–ÀÎÀôÕ~[cYM‰h+76§.÷R쉹¯&Ѧãa®—-»Àúƒ±÷®Ýi$É¢èþì_‘w­³–A*U¼¤½·öº(™‡ÈjÍ7,a›¶Þu·ç×ßx仲’Õ=3÷ =cAU>"###ã•‘ÎéãÚšªÐKÛJršÚÛ)F®ñ¾E!Sï¥7æCW›«dœÔ»w·ïäQms¾ÐÓÎ ­R/•þ¦˜Ìÿ¼ê£·ŽÔvN‘ä©âÖù@¿7í{†ëNÀ锎„r(/Ît¸Éï¸áÑ7SÑ¨í¤©¸œLžÓ öøß¯ú¼“µËeåanÏ®dz(—®¥•ˆO½ó©vëðûàµs²]7iÚf¥ дٗ %j±ÝT Ãb$ƒè<þEI¯°Çbüõ¡ãRnAm͑٘pqà<4à8Ja“­Fi-JëQÚˆÒf”FéQ”Æø?¼mÉ Ð8m~˜úR:¯ã€Ô]ê·lS³ÏÿÚÂ݃§d¡5­Ðó—m}* 8Ãåîe9.r`ˆ¦2|9Ä®Šÿ>×cýEH⨒@÷½2ÌÖÞ™ÇÝ>H‡N¡S†Êýi9©Õä{íÄ(¶îÅɾ¨º/ #ŽÅ>½u_UñUB¯¼75|SÅ7îó:>¯eŸ7ðy=û¼‰ÏÙç‡ø¼™}~„ϳÏã ¾8°Y%IzbfeK FbÂ’G2[å2· ŒŽ€’\Å{-Å7ƒ' ßy¥rhUãÜÂ}ÜÍ34Äe•?ξs‰¬D†£Åètª!ìCï<Ò’/ Ã}Ø%ƒèîÿÛyŒ­8¥ðÌžÓqæ^`´À~ŽwNa•½Â×X8HÚ¶ôGœiÄÇ•T/%ƒB±“쩘~‹"€$öt,÷»á®$ÿ“É=´o Û¡¡lverÉ0Û!w ‘LµÈS`ð&ÿ‰$¾4Qou±šúRW_êK3Ô¡z{¤;ªèoЧœ 5;Q‹ÝŽŽJ¥"¿HÏäsqšq2ºH$R:E¤4ƒH ü‘’Û°i°+ú›ŠDËHË…YÔÄ Pž—²L4óS‚S@ˆ¢NŠ?åL0æe‡´ÂwTð÷HÜôFýŽü ¿†ò'ÿÂ0Ç¡Ö#)p~ÃÒŽÍ×D~Âìò×Ö¸Ç_.® š‹ª–.®Û£‹빈Zƒ‚ÅJUAiõƒu1F‡î…Šdao¨Ê²¯ÞÌŽuCåŸÚ\ŽWžä&ïòFRt`¢ƒè='\‘î'þnû9¥­ŽtÖì}„µljâ=Óƒïm¤´(–;à]F’±»¼Gñä=]–û£ánGÈkÿ´ÁdŸo9žFx<ÉŸ8;¦€O.jÏ1n“û!óÞ¶DOÑlUŠè2™Yv`ú7-l¯Zü´Ä#cêš8¶.ZÃ,ßèâ:â…h¤5 £˜ÃÌ)”4²BA¾m#ÄÉmîÍ–¤ˆ CÙv O»Ñðþßé¶#²…DdÖˆØà± b>b+Ð ™À<þüXû¹[cŠ0T¡˜ð÷Âhý/ÑÿpßHåc^iþ ÓŠúäÂðMqóHñr‰ HnRQ´¶ŠHn ‘µaøŠ¤jmÇØ‰ÜžÓ//¾ßJ³Œ>œ¢a¯­j^¡*rDDFgF(:F“B[›] äËNëduƒq  GÁ QPa”NZƒ‹èœè-ú€ºQfuHÒçEὓ«ƒWM÷—ž^I¼|xñùÕÆ](ÍKÒÖ…§Q/ê Ò!ü\…áaà¶©¿JÉÕF½´Ü-‡Î{1CFÖŸVާævŽúEAŽXšVŠ{q¥\éìW\ý 0-!ß,îõ0k—ðÁqlÿ;éœÀ üÄ,@v£§ˆ.ƒm†j¢zä{'Ž}SqÕ@©êœÓŠ ô´ŸöFð´ç<Ò¢‰ú¸šZì'AìK´£heoà†Aʨ˜ôÒ©Ãøª‰(L÷{E3Óüɸîò|´úyœ;/èç¹æL0NN˜LÕ£sñdTØâ(ÆeQà!ñ{´Ódv’¸Âöx«ÙCT£?E]âå&òHI©Il!I 6!mMÞ)Xœƒq)´wh%A"±G‡XKO“ß ÂE­pj‹Å{™9ä}fHx‹”`"E!¦I)Õì¹Éà‡‘H¦‰—Ø2+«ûŽúŠ•·âÄO§XFkõàdŒìuRè¡1ƒ¥“EaAã YP è(ndæ_Ù]šÞsÇB"”iGÿô÷ëù§Oy®¹ç[`Úíý+ Ps˜òBêÏðQ߆¤“gh¢êO×[¡5úWÛ„¬ »3‘k±t±oI¼ÊœÔîuÛdL”’‚é¼ÅXSþu®ŠâÒ1qtÀZ8ì–3ËV/£ ®cééÛBÉM´šBñë|nà3;΀ ý¸Íõ QA´è v³X¤Ç pyþ’ÂÓ"™?ó((«Ã†ò`Üþ–aÖÂÔa¬çJ†s?;ftŽàŽ«~$öbãØÅEÄEë¸ð2èŒ Y hÔ³8ö†£O2£¨¿,U¨ tlÁº;ˆ;Í‘ÍîHÖzÐï>¢®‡ÉI˜qÀt€u:²!Lƒ(ÍŒ&›Ežó^Qq²ÓŠr@"“§dÖ|”ÞÛÌøxý>—«ç_ m¨'œÃ9t¯}äit+¥I9g[™BhÁû¢='aAئû€²—¯wTþPf V滣€ãá¼ÄŠÄP‡]ŒîÃDÊ“QnÐzzj…¥Œ)t^’ŽuÁ™pÈ$gBPÔ±gô £XƒŸÊ¼©’(‡ƒÊBSöc³% 3š¿ýmýÂ'µ(—º#«A¯YzÀ ÔYˆCPR©²ïy7bDH-DY±"R £Œ;^ VÚkn*î.å:æ=MþŠP«FŠ‹+¦dv£™­N‚T÷eê©Fqñ˜Àx‡e¶6LÇ+Î#_}ÆG87r|½‘§-Ú¶*ØhÔ€­JXZŸû˜ŒËîSOçá_9žHõ\P@+x§0ØÿÉ-“ŠÜ÷{$)Nƒ‚‚Äá‚"ñ‰”Îózl·% ®cSœæ¹ë³Îž©åŠº‰†váí¾&ãgj ²^+é®B‡yœØ1òL@À©ÝÂVÒsþ#« +IºŒØÄŽ#F/®Iø‰ÌÕä†md"?NEÏÓ‡³÷(9z9¼±—¼em²DÐùL¾u@ȵÕJÆ\!›Ì؆ÛÄ‚Hýåß&fÕØ#ƒ‘©;@»7ºà˜ž*#îðý”Òúâ{`üëC×È…®êCÇò‡„ˆBõ輯Úä)<˜fÎ%Z¦„œu“AªçÃÕÌ…«ö<Öìñ]9T€-h1l¦Z1ì±ýÓØ·hÉ –u€¨ÌejSÁÝìê¢Csev¬c 2µe•:â™í6i“'ex£öÔîdJ9€¥àU`ò^ ´QæE­|„•Dí³Å„üº“t8éŽ\·§ôTÉSÕtÈk^¢-š Mn¯~ ʧ#Åå>‡}k‹vÉ‚ÒÅñi;ø¦¨3u ÃÝÒIp>j0f€ 3eŽi+ åÁðy6ubo™J“X«Tj¶AÒK\¢Óê¼&úle'ìô4›•M':!4—Ìʾ0ú({Ó!öx½ ŸŒ¼7¾õJEeñD°ëI¥üFËÊl´ ¡öÂû‰³E?9VFéÀók#¨Sy`HLh7©êÝDÉþwŠw0çÊp±Ez̘z@h«äÈÖMª¥G’Þ, +,8Bâ»Z…éÀëìϱŸ“Vjâ¦}^Œe}çýŽëŽ?Ž^fö`B2£™v3f½œaëxÀ4hªÅmjá1c ßÔC8YÓº«‹ùó·Å©»ÅŸKÚæ;Ò‘æ6þ\÷,`ÊiãŸ×=ûoo,}þ•¼±»8ÓvœãÍnx¢üI Ìþ¶5Îì.©¼{›}HŸb¢%=çIxt‹™É±d盘𯋳•°‚©¹QÊ­)ìªSN(Ñ›>·¬6xN G: kHb/—(ÇtÄËÒ¸¶¼ð,ýȧÀÞr¯nT|æLfrÔùi# S”@ïòµ×Z±I'£`84 , ü×ÉÖJ9ÆÕd)=ëé»ì¢ÊV³ÂtÙ(0}€Òa›¾½6¼Ã7¼Ãœ OºÃ­EìáT:r‰Ï¼É: ¬ÀÀÒuL&Î"‡Á–ÂùñŒ­es¢‡¨e#=œmµÌ˜)ó{¥lpZ«?S­¬V®·¡¬cª4ž«b9ñø¦&»Ãæsµyq½Çc–ªÎa¦ŽÎK§oý"™ÆÈvÇþ¬L±yMôÌfœ'=ó3[ÛUO1_Y·8åž›p/Ô¹Jh«Ù:O nœr==‡-ËS‰Ái$Ol9 N¯[fyÉZ"I0Îw‘Ö3¼H´‹Á×WCÌ2@™þ\NĶƒ´{åìø 'vcCeq†“e}¨Éš Y¦ò v䪒Yëþ‰~NU8Q.ESÓ_¤'­Ž¤C÷H^fm)5ïëýu¨R4ãt‹•éÒʈ¬BÏes¸)áÄþ"Õ2¼$ñ}ñ%~ÈoöÙüíÛ«ÚwͰӉÙÕP×yÙùçÃkœG¡£9Áþ^À{Ø÷–ŒâŒ¤‰÷Hym_¨³²K“:P¢ÈO,Çž¥ùœÌ&âÊMbÐÀ&û˜–ÂiÔšÎKI±Xo£\(+(¥1Õ À2YuØ<Úª”™VÎJ+yެFòÄ)è9/¥L]éeÚÚýmYß¹¹D©ûv¾¾ËýØ\ÈÃðŸ´p¹à}Øê¶R}:Úkh2u›Jü¦èZm÷ú”é¥I…'kÖø°áGÌÓἪçW“©º;ÍpÀ¡Œ€äŒ«/Ó1¬m~N2%e'Ø%ïsr.ºãéd*“ŸÚW ©|†]¾1@=5Xð-Ã(% BèÕðÒ©èL9¦ãè–2–jÌ‹¹dZ'lÚ!XÚ&Ÿ½Ê%#Q&/éR·\á£3X/°¿ñ~.£ÒɆàÀ [^–â(ÿeô\íýøÔõ—ì'ÃËWî$Ý>Gò¤/ÓËBý;ʇÜ*2oM¨ožøÂaT õøÜf´ëñ2‡/ªS’_í)±!Å È6µƒ¸|Éß þNÌï*þ®•ëžX(ßÖðm³\­Vu…:5X)×ý¨Aªåf¸‘&½n–㺮qHPTÊÍÚAèÄ2Áߤ†:Ñp…áN| ëôˆ€Ô`'®0܉ÒÀjåZ#îª g‚\üUñ‘- zÕƒ³NOü5ð‘- zUÁYÔŠ„`SÒÛ-v7ÉÃc세| 0H¥îk^hÚIÇ:½';•úûÂ)‡Â‹7cUrÉ¡%ñRºQ Q9ËŽ‘Aq™6íX}1V?6ÛŠ’JT­DµJT¯DJ„§ ¾”)‘c}éù?®{é:ÍRÅ~Î]²Y21m6Ê ëÓì”*±n‰Û©"šSBpT®7êIܬ¢îUË”¡v’²~_k&~J´YŠËv™†UÈ@Õ  ^®ÕÍõÀ`YÙEÜ5Æàalýb³ÜˆkI\šG£zpˆÕrrtT;Jª‡õæa#ÓõuXn$GµZÜHjÕF½e»LÐpTŽ«ÍJ½~XmÖU»ƒ†šA°…C›  ÄyZ㧉[¶ÎOã$D^r½Yhuœ¿ðÜÖÊ•JR=B#Wõ°8ió¨Ú8LêIãèðÈ/SçvjÕÃ$©5ãJ×|ä49õr³ÞlÀ$$qRëyÈ©äÔÊÕæQ½‘YáßÔËú-þmˆ¤ °GUþë©óš•ÃJró_·Hƒ§¿Y?Š“ZåþVý!Jš>Šã# £¸×3KE¢¼vTLU«õFœ„—S‚dT¯%Íj¥YkT‚(?*W€¬1L`³v×+ÜT£V9Jšf#Ž›M¿L“fȘ@Ü„˜£¼™iØ3S9ŒÕ¤QœÆI%85GñaµÑ¬Öõ‡ÍZpj›Íz=®ÀÜA{ÕÀÔ$e ßJ¥³ÒLâJ3051`´Q?:lT€‘4½"M^ ²þáa­Z¯fV¯âHµfý°Ù¨Ôb˜ÆœÙ;¬'õ:tXmT¼®Ìì9jÖ+Àtªqf†%ÅÁ»j³Š­V23Ü`x`Ö`éÂÔ“àÔß…€l°c¿Ì!MoV9ðÀ:´5r§·i¦&J׎ªq L¯Zyr\«&u˜™CàxI˜ÞZ9‰kˆÏjµ( OïQbýœ]˜Ü¸RoÀ€uT³—ã#X/ÀT—1êåzå¨Q‹‘‰^CP9::‚—@sÕZê°4kÀߎªõä0Î!à—°6pשfˆDlÛµÐdûE†;Kžs4Ô„ŽjIµžYßMž©£:¬Ü£Pv¥‘ἇÜWR©¢Õ¾ ë0ÉÒIR†qÕIrT‰ÍþvXAÔQE| ”IJê׬(…MP7?íé(cj‚’rûB¹f~&ŽÁkxY´wA*“g"P¿;ÖÍ—â(öâus€ ‹¸ma8åÝ‚Õhiu£Ža%„ç(m×ÄNŸÜÔt›¸R#­ˆ¢3@¯&|MôŠÇf3§ç…çžÌä0F2%_IRjêžö œ*÷’¥¨s~•hèÅqò»Cq~,¹G’}( •bwÿÜÈzü› À¦úà:Ç1 æ@¢Q‡â©ª-ºŽ%ÿnçðWVYH¡Åavb DÁ—Œ›¤Áç#½YQSÂ÷éf–â í]ÒØqRpÆ}’Io_’¦Ÿä×1¢²²L†t'8)ÇùqZ¢Ö£t?[®ÏqŸ£tXä# ‰?ÔBZŠ1‘ò¹²ù½'Gõº·Ó ¨.&â<ÄØ`c ÇÖðÉ6‘^ûHª}˜ºGòHõØû P[Œ_)2Ù?/É…ÀCˆ›î!8ð{$›=$ÀŒ@eSÑ¿jEs ã¥&Çô¯ÅÕ °P7ª ‡fiuX³±~[dÞúð‚ rH¼$,¶“H¶“‰Çu—­‚—-Úü%‰°ÆÞbܲ ãÐLâzfñå/;¢¿¦³ä²f3w¹mYhͦÈ+™ ¾­ÆîOŸB]6”G3ƒíœ•ÇØRÒéàäX/µ KÚa£Á©„F¼ †žè¥ù[ÒCÐcMê2qb@Oâ AHý1cÑø6e†zl¾âdoaHU—®«IˆÌ­é¶†›ý ±ÜÍ ›DH+ãø©=)ï;™gŸK´­Ôk#'oP¨‰4Œœ„AÛš0P0/¯Ö(ßñ”e$dXÓH‹{ê4^±¸ÇwvÔ‡ì£ãŽÂÒž¾å££õÝNñ #­iÚH†1ö2ûÅ^gO¿Þ“G€ªÅ=çÎ èo\¡Õ"ëŒ+ÇŽçò#Ø*¦´»‰½Õ-bjpœwwNAwçÆŽ·5{ÆXž[dÍ~8žƒVU9`ìkº±âå>·¥ Ù‚UÑI“Á`jxaîÆÎlÂ\˜'œ%O^ïªÍrašw@u8d(ÐÕ¹- âžñ FJí4-–ÙÖ\S3MPhÛÔ ‰…Ìt8„Ç/‘aàs[Åßï¨73ɉ;çÐBNx ÿßw§ôMÅÓ$£0ÓÃ&íÁƒ>ÊyÿUÒ€l¡ÔµòxO¸iÎÏȪ iÏE±Ëi餣Q‰Ç¹â¥1߸¹8…ú úÇ®iŸ]»¶9¢ÃWûÖv hi†R_Ñ|«QÓVAùµ¤ª%¬6‘ÐRs=Ù;lOfÝK»ESJ6ÕÂŵֳ`÷#XäÃ9µ §«Iù™&k9>‹'’¿¬/èn9×Ô”{z”¤‰s…ý,B°“sÜè/ Õð™ ˆŠn»€6 @Æîƒ·Úyæ|gÀ|±‹ ˜¿Yµ$œtµR†óä(•®<ø§5<»ê§™OâFœµ®&ºê¶Ÿ 囔ަ©”B€U}É«ôªW0FÔºí~ Ä9W¦I·Š*Û"ÎÐWIÁÔ§rNQ1N=¡;oÑ•o;èwËH9Wx6UW–çÏ"q¨œ‚ØÙUš¢ÓrŒ–{<;l!-õµò¢€×eòÕx¸~éÜŒêô'€øFxÿóµUzˆ„_@)j¯`ÎŽÑAy8°ˆ~»Š®BžÏ _?®ÄxRl’2Tÿ€ïÙ+o—–oC®¸#nuj•û“+Žè8íèÏÒæ;U>¶QháphX{- ‡?`½'Êôü×7vaʉƒJS§ˆõ8N’~ÄÛ[øð8œqGê]Õ\»|RL—¡;{4N§½¨%ÕH­\Û‚®J†bír«Ü.«<ãq]â£fSxQNšÚ·üfëjgï#3‚WzÉÈEŒX£ý¯>÷!úp"v4„.³y—nÏœw¶NÒ¼ú% ƶXýtAü €¥}¨$\sáPÔø@;ÖgÇBõAÿ24D„½3éœDÈ@>)•‚ü=ÀßEj)ÅqPõ%¦ìF?A#×~g÷2Àa~(š\V „“ϰzÌMP[ì¶ø§$JJšÚ&¯gÃ$wæ©•j+Œ „‰¿íQ¥jl¨8´¢q^tšÆrXÞ›üfêÍO`hu;Á§1¦ù¨}º£/û§·rÆ”1px†‹&SàÐ"`ÉóñoeA)ŠV„"NÍB}?AnYPþÉa]ÜjPf6jd–Z^(±àg·³\o£“ÂÛ1EXC'чA¼•3æó¶·ÞZr·hØ ÷0÷퉉”ÂÓê?-¨IùÑÔ\áLa!r` hMUA¿ÆSIR¢A—´óJ#"¡b@‚“<þ™Û¬aL¡pÅÞ¤gÌ[H06JÆ] K‹†Fw‰_Þpó7 ÝÝ©ê[wªä%;m"³>) ÌüAÏ>ØÏ>¸¼2;a“Ù‰´mZü/³¥%+-3×'Ù±èQ81±ûAì PBм½Œ²9Ã2{RŒËs§Qdö%ÏI,ý„#·ñÏ˶;³[üX. ¸¹ÄbØíãÓ§õêi³XÎÅÝ—OŸg…Ù§»èþn-£‡ûèá)Z|ÿm-–ŸW ¢År3ÿ2_ ¿FŒa9Yìnõôé~.¾¯ç·‹ÇÅj) áÖ¡É»³¹Gñyv»Y­Å,[çÓly'f›õâñ釘ß/ËÙ^•½FâéñivÿCÜ¿ó;,¯nW‘øô´‹ <‡çòµª¼€¾6Pé÷Åæ+@ð8ûm±üc›ÅÃ\,> ±¾]ØÁrµËùün~gz çËÍú‡~i4|±,š’ê]lf‹å£Ø|«ñ.äð9³/ó² —·«û§‡åc¶‰Õg»òl=§Š€‹©ˆå@h;Û –¼[̾¬–³ûÇ­m®W¿ x¸ß¡Ô—¯"ÙƒŸOðDuZÎÖxœÏ%|€ÉG˜¢ûÕïâój-îæ€”ûDz[@¡M…áÜÏgw8w0‡K"$9’Ùz=û‘ ¶ýðô¸A*)#Æq°–ž_Ž¥ü»ŽÕúŠì{µ^|â½—ètZƒn¶·¶|zøÄM™ÙaDñÁ„¨UDù†½”ï7e€ÝíüéÏ>­~›¿¨ó'«s¿ÌP•˜þ¼¸] в#`e=³ÖÖóÍÓzZl°¸Ÿ¾0¹³å—§ûÙ:g%åSþÃÓýfñý~1nôû×ÅíWñû{z’߬Äê.R`%`ufd‹¿ƒRìæ÷õb³™¹Ì€¿ßï®ÿ ¨xÌ ØÅêîévƒè†á<_¯Ô<hϨ”ÌŽ²ä Š šiß/f°_l‡A2³ÇOãbóàÝ&r{.#q& ÌÚT#¦ÛÕ=2L ½/ëÙ0å/ÈŒ&hÀó ÕZ,¿?mÊ^?ê«÷X¨§ßw°µf¥XE€Æ1#·¢a4ÏTD'®áÖÁ2w+ %áM,s-(7>Ìþ¨€&~-=<…;Ä’‰ò/¡äþChÜ3Ȳ (¾€FI^9ø|ÃB µþŠcÙRå©oѯ(6Î ø’-ËQÖ(\,–OÂd˜—ÎkZ$@¬´ÏË}]oìÖΞ³µmÏîxÑI[¬ac¥ŽZ\,•¢ìgoýÎïç,|™/çkX}wâîiTŠíN&ùmÙƒЬ6À[ÌæEý²üfº‡aZ£É6"è®pþ"éýüóFÂpO v*ÃH©’`†-`÷ÿjWa#ëZÏ?Ãn°¼µeÊ{XZ³Ûoež…ß`7ÂUG(¨ĵƒæ¡õö~ëãau?_G¸APñÍðrþ»x˜ÿ±@x¶†µB>KÏ€—ûÙ'Ó£a‡¼i|~ZÞb¹GÃ[îgÂßDwÀ΢ÅÝ Öˆ| s·YÆUá‚Ðõÿ¯—Äã×ÄÞ°IÆPFÚßxÆBv-*ѯѯOѯ~…¯q»Á÷8ºî"øï!Z>ÄØ£¬ï³Õ*ìHhÇR 1ˆ-uà}îVªÐòµ¬õ+FŸQ;Ê%ÿklýCÑRªÇà%I9¿VŠâË …-™Ïß¡6 š1ºã‚:!!ÖýßÍ ‹m@•‡{Çtˆ ÖýßùLj客5f³ª…»È)£öO¤ÀùõÉAÒ—ÙÓãã7X£{±²ô}¶&Ì‘ ËR£ &šXz˜Á§„šXa&¶Qƒi¿IÆü`¡æ™ÄbéfÑÜ-çl¼‰Ó@èqýÝuÓ$ýÄ{E$¶µ (A9`xk<-qfVò&¦¦N¼ØØ¯{ Ú ð3ì÷7Q-bÍÿ°wÿ ¨4ðeé›e¨ÆZ¼p ÷ûq„à<€øÄñÖ¼ý ßR\0ßàåCÏ„”Œ™)1¶Åì~ ªÖ‡£ní¢“4[~»Ó«#®T|IÆíWhŽÔïå$ËÇ)Ø6ޱÝ{nðA5Ö¨ø3±ÁÍQöš%‚Š‹<äyà"ij÷æÐ…tX‰=Â*ňƒ`§(( b°0wцçæfÏë ö³ìª”Côb/JþÐâfªAùX*l{’ŠÑÒ…åH,ƒõ_¥"+S!þ(³<YÌB. úx½'r+yg…t—¡Wf*ÍÌ“M ššjB· &ý!К,FïÔÌ7­Ûé<öižÓÜá™;þ¿~-:Y̽öŽBù#LŒÃÂLºyÈ}îËì±»ÄÙÝ€¨a‰_ZÜ›‰ué.aÙ“*'usþ1_6`Û =ËènÝÁ¾¾¼ý#ºûê€7³å†Lp¨°H}óûý“ù¥Ä’QŸ–ëÙüîW«ï¤OA“k)?Îÿ÷ ¶)Ôß—ZÉüä+ Óå´EJâŠDõ ŽAº*ç )w ¡óîý;ËJ,8$OÚÕâŠ'°̾´ø\X¢]£RtÐ…8¾›9ØõÞ°e|—AB+cô«Èt‘8|ôvu7'4<-yô:à©ÿÌf+(”jŒÅî?,¯øâ‡ýC‚<¡R¤b…Òr?.îáS[þ¢r?d¹N¹V9#ó ÞX€ðŤJùeHiæbñ‡Y¿ÔùûÄ®ÍcìkñƒÿB’GõY»’Fá§°Õ9±Èi*ÜÏgË(ÇH„Œ7XlÄÐVw@òúl óT Å­j–,TUÃp†¯Fo ¾–è°‡%séš°) „¨\„×¹G"Õ¨¶S¯º¶¤ ñw]~ú…«pâN2…«Váª[¸ªâýÃSÉ?rØÜbm>dø¾²ù¨q3Í”væ;¯d;T fñyÁFÇÛÕ]hšFôÀ»ürþöüßæ¦»H$ñÁQeëÂÁšpSŸiý±;³2Ìh;û1ØØ‰­ìÈIr81$—Ë8@`N_¸öë?µöÿ«p×5_ùš¯oíM¿Ðk=¸¾ÿ°ÖwpMÿa­ioÛjnÚKº"leÅPÚÐ2»ÖQÍz”æL˜Ñj"íNâ+»¡bäÁG«A²w,ÕÿàÕÌ‚aÜa›õl­d€Æc‘K,|aCŽm>@«ýŸ‹0”w0;^ñE»9_0l#±Øöf·€üÖª¿URáeaYhr`¨‡Áx ¾#ˆ¹x›\û†‰ä3;ÊjåeÃ,æp¡Ìš ¨è> ‡|Š~]}z6Î`¯ˆÅò–… 3€RŸ0i&ðx/`ÿ6ç6xüñ¸™+³ûLì ö'R³@çcaVTOµ( ŒÒ*’AÚL V§8…· ÇòÓzŸ×«‡ÜÞÄÛzÎÿEüàšûe®SlmhR¢|nª>É¿:Èk _‰€Ñ!©udS–Ìv CVµ¹â•¾Ç UX®–d ´+¨E¢êå¹»!¨……îöîÀƒï«Ç¹³^²¬R! ëÐ+‘ kÔÔ&÷°q;‹Ž¼¸Ì¤—\«ÛÛ§5*æÚÙ)×·‰Ö™y†ÒÕÒqT¢—z~ûu¹¸¥¸$öXKWò£íµľèÆÞ`ÔÀíŒ|cØâdt=ÍÖ_ž´&¯žšç´Æ#%㊠=n½Î ¯=G2‚J +:Tb’ý:{$?0»±É’^)WLmEÒº Ù‰¤Ìk¦„¤!¶—B t[Í™·ÞÊ ßÈcÍœBÖ#‘I|ÁP(¶Á!˜á†`Žþî.#4¾ð`üV@ÊÐŒÚËe×+Èb„t"÷ [·ÅÝÈX± ˆ^ØvàÝJh×ßk½~ØVä»þ¾Eß>¡oÝb/»ø¸ÔƒòÉ‘—O‰ƒa¿ò½2hà¢b9s<¾ˆ¬/ÒÏÛÞqŒä¼æ÷÷{?ø¥ëãxöç¬ßOäù¿ª«yŽŒ?[<>²ŠllËÏ?î·ο—LÀ Ž•©lÛôÖøH⟵”Cc ëK#y²‡Ws½fKä4>Ñ䏨m÷퓊ÿ°AúF¤ÃØoŸœWrtø'ì´13óÍõË×3R¾KPÎ}þ‰<›™çä#Ê`:„3Xe÷ŸÆj!Ï€q¶ W“Î,¹¥Gþv¾}QÈbOÅìâ¸C¿œ&ë?oÈL?yØñ'µ@KbãNmc ã!ß³täGÏòƒ MSk–!|“ÜÎ#W±«°HmªÒÂËÐi<ŸÍ„ØIÐ —ÇÄK8MžOn‹cÍv}Uv7(eö,mY"Ô-ó}Y°;>(usc‡vn~_IAõñŸÃ•Zï÷CR¾7 ‡o9à#lÈ{¶ƒùÿN§–ÄÿÝ—&ì=vqm±^xŸqkÉù±'÷/ðtýœµ;€FÉn†o;䥦ïü®å/2xïYž.®»',ë÷žãÛR6î=lj¥ ÛêiÐÄ ›PþüñËÂfý¡K1éÊô2êv†Q7ê^]D˜Ã¿Ûé _~¿ê«Rˆë$âéD'e×i¿'FÖM'ú¡Lœoã¿ ª¹ÛùÏWýÜùê¾l‘Ý.~\öF˜ÂÙ¾eÂä&êàáJ€H’ÿ¥âÒäæ­ÉdÔN1Û:çÜWgŽNÕÑL˜J@—sÓI‘ï¹Øµi ¡ ¦‹§vMcWÜ\•š«îÜ\/=ãÜò%C­zæFkÔhM6º'¯ÓHê ižöøß{öQ4½)qÃò`žì%t|ùbÜIÛÓ^o|õ£ats1Ú¡<à&Òé«n­xÅ‚È_#ÐB:-ëNëLÝQ˜î÷ŠêrÐ^æc2oÔ☊©^æP¢‹µiucYuÞÇ.D>p1²äÅ“«þ”³ò§jåË(L¯EÀÞ˜A0î o8ö—0ˆþÏßÍð³Yõw`.0itž¼>7þi êsÙëO»>câÄç‰p/‡_T­RÌ •v<ºä9Q·V?wÈÏábz|uYµ“N.«pR1;‰cì.Ýmk7Ž[Ó¤pyya>aXÃ'Ýi+‚†qm{Q t£)ÿD×£ñ‡®lˆïWà[oˆ»8wßà¼v1_Ôà”¯ÜÑ©Ñä;v#¹oLõ'‘w'Žy÷Óhx2§n3x÷À%½Õ çìfç…2ÀtÝ“|ÜÑ]%;¯ZB€l\6„Hü·^è«+ô¥[®ºÈÜoAs€•^rÑÅ[Üsñë6ÂIíœL^p¼î]åÈáK,ép§t.ðLV3ÐUWúª‰¤kf1·Òg9ðyÉÝuy^œŒx­dDœÞ‘ØÎ³é7™,8'çËT³à¥_Nòª©ÔÆØ÷¾ØžÃ¹ú‚FvÌ%í7’îIýØù¤)‹F:dS>ß´•LnÛ˜6âuûòB±}úåõ¬¾[{sâ[¹ôd·Õp·‰éVP ¥“¤û»@Q 0öö€ãçò–(À¨u:L¨T·¨Ï$Ìô€ÌnžVNÙBIÿ€­7¤=• gødZ,Àž%wÕüë°«š³Xòº‘­¾ƒâÁyœb¼$)·†r~B㣣8Îô—p:™8 É«s¾½çBæLÁÃ}hCf–-¾£Ú[PЦü­vQõ…š¶"„aI^By§JÔMdw’N®(¯ fɶèžê´ÉôÃÊœŒÍÉ¢”a»ì¥ûíxï¼dg^ÎÅч 9é>£'ÙJÁ˜Qó00èØmœÈ >·€R΀Rü „TBÑIßK(Ê›A$Ó¡²ðÃrTÅØÆhOÂeMƒùEU2›J^Ü ¶hçêÌkÊF ¼Ç­Ì‘‚ýË’ aIÝ׸3²²°’éÇÄ`«)Z¹ñY¥¡’j8,.gRîLÎ}‹®(Xó—}AÕÐpy(Áx`YF-ÑÛ–jw‘¾“ÐÕ,B©òt|Õ-¿cçÞÖ;0\Ö¸§`gžé3Íìí.Ó¬½ŒiÖ~ŽiÖ^Ì2k?Á0kÏ\9ó2†Yk¾v¼‚f «Üß•QÖÔ­4šM"—Ýkǯb”5÷ %‰—QÖvc“µ|©AZ>Oñ¾ÃÖ¸+èæO2ªÀ’š¦­þ„ÊŒ‰ð ˜©Š W}¾zü§sUe†ƒQGׯ>,ZðS·ážƒ‰˜Þ\`‰ñ@>ˉ·QüÕœ¸þRNü–Y•Ñ„N–;ácw|F¹k‰¦hu`„ &VžLñ Ù®ºÓ*¬ßâ[x ÚÜî³5F86vÐå²dÏK->´…”ßhL }˜—4#ÎË7_!…ÚÌ8µ¥|„W43¼ƒNl)-B¯Üí; öPè쑲,¯š‰úÃí‹ÈØ"¤/­!KQ#ñ3ƒ¡Ì®þå1´8ôy | [v^º¶,3Âw¡_Φ®s¾Öü>ó;ÌXάƑI¬þ‚?ÓÊ™îÎ.rzQ­m=˜¬è(w<>œö[gÚȦf„AÍ»ÑzM¡Ùh ]‘ÝÏ©õœ=ÏÜh}Óõ½.o†ô -‡lÆÃ~ ÁNwì›ó9ìpÚ07mKS¬ÑîE4 }_5^xM©Oû7>¬¡[®uöðÌÐrHÀC;8zä^ ­o™Ö–¶ž àã”.Ä™_ö«ÒˆŠ;O Æ ÙýrTŒ¾8ÝŒŸŸùx7‹“VûÃukÜ1·aC§¸N>Eá;‰QÞî·/Sؤ§¬õÈûƒ&Ýnæúú²_\ûк»Î°pºè.GI%B fÃ÷‡\´ƒ]]tȳ˜ï¶Ú=¦œiëCw¨€é™vðå$ý[W&·oMñJYß»¿L©Pf =º©½?펻úvrö.âÈÆ£¾•7¾s5†™ò[À’HËØ^»…ž0ÑMéŠm¾Šýc—îÚîž±oíäjê·’N't;7Hé Œ»L²¯wôi¦ã¬Sât§TßhZé.y9Å­JeÛ• J®>…2ÝFëlƒðG.8UouŸàµô7t‘7ÝDÐA'akx“ÁH: 1r²~LÁ‹ó&º@í©¸‚u×7³Ò“©Áhž*¬¹8AfÔ´É··_¨ûíG;ãô£I]¬çÄ\žpšŽ'Ò½í®ýÌŠœêêÒ™Œ®*œ¼6¡;¥Lëq”$QB×Ò'5Dƒt¢Ëvht90.ÁJcÐm!0 ÃùT ‹kÌ^|Õ†u>9½êJ—b!µ—W ×Á)R¾êwh"pq´{i÷cøvúŒ|wìïH\!ÈJI¸/> F ÿ&—CnO ¦yîkjC³KÛN—UäÉã1§}¶¤`g€¹½©óVBã;ŒÝWRhbTðdªÅË®pZJZK¸Öܰ€ö·ƒÓÖâ…{Ò=K‡Äî­«íÝÊ4Óš±àÞ“LœŠs âvº˜‹Q´Ù(­eZ*˜ã[“¹®ínõûtJ9²ý=K<%—XPåNϵiÍeX.k5ÌZ€ÓkÔÀ°3JâB JÃÓ%ÁRkšÅõˆáúƒìþ’N#…%¼'…e2jOg<·V?áûʺUæ†Ù$a˜'*àÕ7Ò‡F \÷Ò6¯r¥¹uØÉèãLTa¨ r L«®ÄZP¹)˜X°Ååx=ârD˜¨P<ÆE VÈÉÃDðÝá|Ó˜¹¸V«ƒ}ˆTfÔ–â“Þ¤Eà Ñ‘_ +Œ(šÓÀªÞ¬†(s{:DB¡N4éÂô¥lp‚$¼(s» PÂ;»Xã4òÙ•Ž[†Î®ðÞIçH Ê‹s³P†ø8u¶A1·xèÃQ™rrOé)J4¥Ùžò`…ŒDPPœd6GaÃK_}ÓúÏq>QwŸXa=0¿c¼Ž‡5Þk´0én³ÍK8,T€X#û4}Áèÿ´¾†.®‡°Ýv‘̈¦0µ!!Û½8+°Q¨fÿGn‘C‚@ ´Õ¤$ˆÁÓü-ApåagÒÀ² ¨ 8ÁrˆÐÌó­0[ºžŽ†¥që¢7mEžõ¡sœšwº—Ô¼Ë@.nX›âIˆPSѽ†•,äT;nÚéÞòkù­èn']+ŠÌHí«1JY´’þ1ñ_ŽIU÷Séòª –èÝ“¿’(6Wn[WŠC^äýÁà­ä«(A67$&b#<„g~HLk€-ëvt„ŒŒ‰Q12bTlŒx‹à4:D)R9ÿ›D)l`#@ódGçqtžÀ µ£ÿCsŒcÜR%‹ˆ´«àÆ …vº£1’½”ªÈ¤SPr&½hôqœvºQnœƒ.7ÄPœ_X)ëO¦ô%/4xÇh6Ó´/nZ㦃ItõÚ=xqpš?vo‘ÑgÌV)2iÛÑOœ½*‚ˆÍw˜öýÉGÃR”NZƒ‹(½F“2»ººˆx—úÑ Ž‰²`ùóß½lÃkøJ\ÆShlp™àic¼²Œø—ß‚6£‡—ÚÔF;„²¸M=*jQ²Øáú¡ )\­&HÊŠòÆç‚ •¬„DÚ¹oÅímQ@?PXÔU8RÐËÁH(]”1j%6û8&FÓea|£j"„5žq/#DSl6ó˜ÿ$´bUdE9$2‰HÁ?PIþ:ç_çr5¦8²« Û:Ëxä%>n+„~D5ž± N"h¤?’ÌWî+BÒ`Å&rÁÂ_jò º'/!sJ¢‡! »2€-Šý86åOÀ]Ò\yúžu·\Nœ[N<[^üÚíy?"HÝö£“ŸZïÙ× íèol¡•ö0ÖÎÐÚoë>éDÙ7begÔÆØ›ÎHicPL;ý:e!Δ‚ªlN$ó 0Ⱥ²Ši o{ÜmIé£E7<öµ¡I5‡  †nŒËš‚¥¯djxŽr°s”T´½ ­î^D–(ébÌ1¾ÆÛ™cs…&Ê8H¿Wè®mƒè2MC¶øÉŠºÎ`÷•f+ jp“²†‡ôT5â7¿BʉªVÞÜœ»ëñ§¦/ºK®¢0džV^J ÖÛ³°Ù05ܵ1¬\ýD^ËàWöðµÖű «#Fr\)'xøCƒ‰þñi9ŽÕûؼ^Zq-ÌçÑ ¥E â¡ð»ª×6L±µ¶iÊàCÜAÕëŽu™¶ë³fNJG%- ˜±úO¥Ži:”*®›á§Ì‚Ýn˜»Ï£Ê[Ð=9°x;ÀÉä°ÚØøÁá#X âqlW°ß&øûz‡Bz<$5´ÒL«)!‹Œ3; õ„wíw|Ó²þI·$[¿iã·°ü`7çÍh[þvð+õj—Rÿõžáæ(ç=ãM-ãi¥m×Þ9`Ó;VüûªNÛŒè˜Ç#€Ñ]é¤p˜ë®z°+ÓF–É—_†Ä< öL Üaÿ& Äy¸TL‰úÝ“+·÷V ÑðrR?Ù ªòU E¤¢'È©2ÝÏãExÔMÙE`×Ã3jÊÜFžiOÖ¡—HÚçRÔëOÕ6 l»j¤ÞË;êð²Ì'騍¥Ã=äv ì TXí$xDËÀâÈ”)ó:e>±›Ì…èhµ‹±-‚¼„[ð;æ !@6Ch(‘nÒáØ2GËâ‘d³FvèïÇøçbÜýh"§Wcr‡É+¬qßïɲ…FŽá ÛÜÞl´·Gâ#…!Êá,ŠƒHî8ÕÕÙçAºP­ÃGȦÆí=T‹$vÊ7ôC•¬H}ó±D¸¢¶VY¼‹M1Çâõ<° Ù:’¯lÍÉdÇ™ïhOõq^Ä· àº=ZÛ#Ù÷gD;ã“±Íø¯ÓšçN:sÑp˜.i2¾“âtáÛl<-Ï<)ã…á^ÏœáÞ¥Ú¿LI¬±çíE T.S»Ì‘P! Ÿ•°UÖbÙ“Â3FÿçEYIû1Ñ4ßàeëfü,ž÷Êþ[Vøï}Ôj%‹DRuolµ¤5&É~L’” §v~¢-¡y Ê dÂc$D¥J½BíÉJê —KDŽì œuj€ô·;ØñDvÛÙSX`œɴè¿ÐR(Jq¥Ø{‘^øb™ÈîÈ"+‰€&,¹­’‘(zH½IŒ‘ zøÊ<¤gÎ2X¢»æ~\5ÿN\«Ö§=êxÏR ÜóÐ5wŠÛ’›—ö¡Ú~U‚âÖ R¤ïQ ÜA‡Ó*4U–ÀpÆ1ÇË©dÞQ ‘ÖéXÚIAY½Hµšc[–¬@s°7V+Qíxú[(P¡Á%†Zœ?µ/Y@F­zãcñ ŽcÂÚ+bÒ£ ØÔÚ]oÏÓî Ó ÏySzÙÃ,]*‘Œùî¡ °×êØÆƒS7æC:ì8âxR¬—Žà­´EÏLdïŸâ5q—„œO©÷ýèÏЖ‰ïyEê·K°O‘HE/†Yô›Ëø&ÎÄM2{K×L` Ó"@·&BãÆî)b¥7‰P’ˆHÀ¡ÛÁU”ºî,—î¤ÝëLdR[Y¹Øº%ç ÈIÊ qÝx*ÈŠå2ûU¡=ÞÅ'ô£½l0¢C@k Ò\tV1û‚D¯Nº EmÞJá 5!@=‘\E÷æf§Ä'`áÍÈpÍÐ=áGqŽ;\—º‰s¼òü<Þ7ž| %1ÐÉ/ûØ+Tç~Ï­[}ì®g€ýÏ´O ëun1¥F™D:Âtéfë LËúTœÈÏÆ1¥Ã%ÖÏ^Ä¢ujãµÂªÈ—Wí­VƒI‘qÕXqPr ZAƒÌåN:§y=lí½)òœì'E&¦UÝ–›”$€4ÝHÕn¤uq1ý’r” .‡7§‰µEõÉ1ƒá<¬òCK !;iˆÐì³IHZؤ“ ÏI§mã[y'”Gl"›<Ã0o¼ ©‘YžIÓî‚8©¼ÑImKQq2FJF# $™hý'EÌÅxެD&àD^kÃDW¸ †Å )oÚašï«Ô‘‡]d`ÑDˆ4sq’¼Xì(?+_Ê9'f.®ß‹rq©­Ñ±)Øê½Ò‡HY(IåÂ~™È· ½M¬·È•Ȩ:¢Äµn9{ÒÌ2‹²úq`¥«¢N‹ÅlñDO2Å ì-Žpn÷fÆíµë¼ðÄÿ±ƒO4Z‘G2 PÀœëcg;¢CZ„wE‡4 oA‡]à.0Œ‘±€ÂÆç¼—I D¡À‚—)ÉöH «”« æž²äº&ÚêI ¨à!&Ý*ÒV ¬&íŠj‡óC~&)úÀÐ9Öcà?Y˜Zxö@¡ƒ¾ýZ ‰€Fª$°q—#ÃOð| ÈOdÉô«°äBQd>Šò4 ù6è¢q_g|5½Ù‰oéz[¿~§.Zß@éŽ 2ÆhÊå©°Ë&mz{FGWÆ#ï(ÃO@‘»p_»:º¾ Ï’1£ÊÇJÇtsL…Àë;Ýçž#.®žjÇÍ“qêi[ñoý01•LÁš¢ñ˜Z/šz‡¸.SdA‡ßäy7³„³'ß0ã4²N˜q$ y³O»™6œo|,ŽN¶y§Ùd Í9罣ȔM;/u/_^^_ªDJÃÑ”íÐò.Q:g ʤ5bÌ<…0ËðåœE!Л}.ÓH,ÝñÿTXèvutô¤\õ[ãtz£¾L@±M$)€tìÒ Ç2U¡C}’Røï¾G„,›ÕêÛÔ;¾ÚEÊêÖ|FEâúæ„´\5Xß÷ÈÇÒµðêeâ4°˜p,!Ž»ó->ùbB&ÈI“/61­ÐQ!ÜX|Ëê âÀó~€èÃk·¯Ò½ÁD [úÈÃÑÈ-»Ç8(tdªŠIúÑhôG#Ðið:½v£6&Ùû7J‘‹ËomìÁRˆËì­ÎØê(DÆÏ— ÈÉ”'ãÂb ßã(Kæ-¾Xñ¢|yªr€!'Š_–(/#o~$èÀÝ”‚E‚öä<‚rðSù‹ñSõ˜–ä.Ò±Á÷‘Û Û3b f† Uíâ¡=dÌSï›<µ|ªedúT›å³oo=ÎQPÉÂËwÅØpñÖlèP×é@àãdÿ@®Á\³Cy }>ëã(ËÒÔaÚ  ±éø¦,F(0_§ÒÞbñ£q÷¢[#¹ÀÓ£lŠ1M°®,O”•Q%ƒGWXÏÖŒ&“”Nݦ§Ìâ, FÃ’ÍÆñô™@‘É¿5Ç’Ó/ÍÝËr)ce‚÷sRüyg@YLá;R:Ôâ°SL{{ZŠ»±‡lÕrÙoïý@»¼´;®/N Àã"έe/(£¸Z2 !0Œ>ÏxCÁl#7óï"ŸætOÞk0œÿ¾Y-„…Z°6¶~9¶Lhå¯ Ç’]Lgr)©TL‚*„ÓJ $‘MÆW«çå0âŽö.<ºcÚˆ•·eSÚ= TœŸ*©÷ŠüO7…scJÿôVÙŸâ—ÍP¿Eæ'lJµs?½,IÞ æ}"”N¶g~нÔOLÇ^Š¡Pö+ ¸–›5¯­…䎶à›Ô h|îÇ&Ò¨P®A;ó9 îç%ǵò$É в¡ÚaùÿÄõS÷\Ø¥þ©–†Su€›e[Ê@çÖl€ãgký«³µ"ÒE–æ¶çkm$¯MØÚØ!Mê–Œ­j~ÊÖØJÙZÍ…ÃNÙ ­å®6!·=ÚáZƒA—ÎáóOªý‚´Ð‘‡~|l'ª¦„Yø9Éâ€ÏRg#:ïKjõ‹ÅwŒÓŽÅ¶SÞÀ‚ªŠ+7ì 3‡ã]4ÇP¬»x·ÃldH(3$¤ÈŒ® ~ªÚì:à•ç ïÙ—‰Íÿpp‡ÖàÛö¢°UðÎ9£Œ'Gr´»C9κq1ª0Îõ( ߥœ]}»ø”“ŠÇx“졉?'ºÁDN¾Äœ”d£)³¦vŒSRݮٌߚÀ–ÞÕQéêZŠÚŸ}²N¦Áî'LýäˆÕľ›Ò¨Ójƒd‹Òý†*÷_c’Püw1žU©Û½nûÃn:µêó…µ°>»i_g¿Í•z±Z²zá;‘>3º„å1I4;£krÖ›dšÿ…RI͵2Yÿ}Öyë"`fÕÞø $ÉšV·%¶MªÕŒlI¡¶ãßÕATïZþÄ6ÞF Iªq.4¾HeÏ·Cž„5fÀúo§Œ$Õfòã,Üo•ƒZ ("˜„V8šˆEÛwô…f!®*’T³ªHéÏ’K®FbçjecÔµ—éŠA4«©ïÅR0 ZZL)OU+/b?ÕØÇ©“îZ¸L×™R»úÜ=Õ8ke‘¨>T£ “æÍ¦Ù°óZÃwTìÈùªùWŒ:ëû5ÐÝŽ^¾»¿%Ϭ&Gј¡£·a¹Ð’f¹Ç?w9õ»|gÉ"”õ› nW‚E!/÷›eñÖÊÈŸu3NÀ¿-:¹E‘.²ÄºÕ¢SM^kÑÁšÛWÆv‹NÕ²èü´A§šoБ=fì1Õ€6›Íþîaø“½ÂÎ2òVsïàØÅÚbå »N’ñ³ŒwËt.Bæñp}ðoâ­X\ÓiW(]Õ(‡žSikHŠRÈö+aUÒÊ⻆ªè‰±¾J0‘_‚i÷ûƶ«ÀÛŠ“òXeLY›øoéíÀ&ë,Ÿ­&ÇoYöç¥ \õ§)f€ôùeø:¥“úÔ‰òÜâ™mÊߌ¤ÓÑÕÄN¯ Ï.øä®fÌ)‰9+(º2ËÚ\O§Â/0ÁdßÊ ªíÊë\©Jû9Ty^Ôµ±o‹·=$<Ïà¸g··OëÙíyò/ø·7â¯ß»ê¯ðFÔ_í¨ÿœ7¢Þxý«¾Å!{$ã•ßz=êøÏ”—ÁWÕTuþkœ 9››nZ~QîK±_…:{õf§ÔùÓ˃p‰2=4qª<´!ÙAñÃK{5rXT§ã-5Jfws‹õu™gΪËc°‰“éGhìÑŽp1™|bŠ¡÷Càý\×hçV4|þ€¯]Ɔì¨h•UÌCöÐ(¶_ÔÒ„p–ªZ°¨ùN—DëtÜž<Ôš'W:¿(DÂnv£Á½PSÎAs3íu‘ŽhŠ€ œ\GåF§ÔPÕú¦Ò¯©ÚbåS»ò~\nšª6A8ŠÔE…6 &q«MÙè˜[5z«iÿN·O=p[Ø CZ”ó éV-Æ9Ô¢®ÈêÀ³qwÌRyŒ$«~Ã/“¸rÜ;ƃ‘²¹=‹|K4©F»Íïrß«vN^2nç§(9¶ t/HÃaiž8;ž‡Ž¦ã°D‘³m\6›”Ræ›'« øôÃD¥.ÁãÕ°|(W?®U²{(ß›9!ËnìÒê¨göD™~‰êf£‰Íacö¨”L$’éà…ÊæÓãðh¬Étcrí»%u²-ÒÒd&a_™%NxæbV»Å3 qÅ´BR#UÀ0FrU¦ƒéh J7u}‰³ÖÐ ´Rä—’7c®Ö*ßÈÀ¦ÈlØ¿oÀ¿W@^)àÇÉ‹ùñŽÉìsìóç‹Yˆ§6vn‹Ȥl°²GØ©#">cä,vNBK)$dòMõÚËû`kr´¾>¥`H›Cu>ËdôtÛ6nÞrò;;JáFÜ«+ÝB!Ÿ^°§œ1:ßfŸ‘Ô3áS£ê aFÅBB‹+2_Dš@‹W2ßBl˰“¨Û†t N’CNi¨ÕÊ®Ì-Á“ξ&åU»ÇÛ¤¾ÚigQ§€®ÅùÕ€B£9+§š4¸æÐnV£çOPõ­o•ºœÃ¿ñ ¿ÔF9?šr;+R±âü¤rÿ¶ìÏ Õ“ŒB‘OÞÃíaO |¢ü„ž3µê©ÔTÿÙ/Hºdù¯<-£Úx30. ê£àUc™-ãës¦²0v§(Ï1vùf.ÇÚ`ÙæŸæwwðl¾^¯Öbþ¸Y<Ì6ógŒ :@ú6òÊ8O(b¨oj&ƒøønˆ"?.§?¸¨±Ã¼f"}ÏBÇÔtØ@Ÿê(”\ÂUq$&ùoÉxüLj§ã^ªXBÝ¿Ô+îY?¿§yhQgNêº ï;A¼Új¡Õ¦eœJi™nrR± “•ÿ:vnjïÑtZÍžñ³¼„þ g‘L¸†ÔHˆGA$ŽàŸDšŒ«‘N´mêöäX'„þ>º¬Me%-Aê;‡åýøeí˜\àÑÉÝþ ŸjdAïR#þ1¡´¨Ì=ò§L¼!S"™f¸i@‡¨1ÑÅgؤäBzÙqÊ"“üÚ:Eá_ hÊ&U.pÙà›¥h©â¢+wökâa:è©{˜„âÁ‰ìT™CÿÌ0]‚\̯°c”ÊËKŒØªÎë-Ø[ZØÑ|í´ð*Ûõ–ÒíA[x©â»š¦+ÑœoË®ÕHD²MÙÒ’ìõ€!®1›ª¾Ú– µÝ1›®­8†@§–éšê>ÓsÞ^„û ƃ¡~°/ÌvÔ¡Ä ®«¶V‰=›¶]ÿÕVmŒ¡W»VÆÀíð'›I,תùõZ ö²¶ïÇE·(/öBÛÅ ŸP¹¸W€µ¼ÏÈ"Y?;–‰1;dx™ee=öüÒþaëLvýpÚBéË®ùù ðÃשfªL­ /\ ljç-ªaþŠô}KÔ’}+€<}ì·Â‚!ÑnYáÛùØê‰n‹ŒÏè¥ÝÖAQÙÃP`g ׌cŠf°Ya@¦•¥ªv)ç`+Ó½ºÀ‹Â'’gp}œq.¦ÖøÉ %£FLv£éh$ú-Ì2å\æå&Päqlñk6mëµ# Ûk £Ð±csÔXgMbO·Je§Ò,A9ôòûîIaÇ输(~FÞ„ÂtD™!Ï̈ ΄ӭ1ÅÖ9½Å»;ÌEדizzº…¼ƒ/˜Å‰BüKôÞ";t #¡iÇð{Ëâ(¿Yev5üÁE„Á©ÀÍ O »Ú)^P\h•U¥¿™+‰w¸õº uqSo‡Û­Õ-ÔÚÏÞ÷<çÖÛrs'-F‡¡.CÁ¶}Œ¦”ûå$èG¹ ©Ï¿ºE;•÷Oýc_„ ÕRqC2¹#—^ Nd5'jkt»eO¦oeGìË#´RXHËݲ¼%XûoA\ÿ¦P¤å™mÛî%¹(dÈko³÷ÝÊŽ—q®vém<Жsj Ê ìÁš ~Jã^ñ ñ„'(Yå’Ó–+óSo!ÃÄô„J;ª>kºO`"¥*+PrŸû-42WZ25ÁÖ/U“¥N2êÁr"¸mªãƒ« ®ÓXLÖ 7 Àq¬¿[åýÅû"øIjÙÑ©Öõ Mޱ€†ãÃl‡±?G¨öfíÁ˜r±Ååë²×Lrn³zgˆ6ºq¹@›Â\ƒ­2â¤PN©Ö æêòùV´ AR3XŽ“ŒÏAfCOZÕà²fQ›™¼í=À§­<Ä ‰{9Þºé11=6U3'a"rF¨y лm¹Jƒ«L;×z¹óŸi—ꇧRÈÙlJiéâÐäpè‡æ3“(„½æñ{Íú.‰bû¢O3ò…œÿ¦YL…B#Ñ3R«[tø\Oq|dJ—âª]·^;܉pÅÁ³ÐÖ$´'­ZòD3õ©T¡ZÔVSØÌá8ºóºì ­›ÅRµÆ7wj€wÛ}5¸¯Dr§Îs´ÍµšÂŒ5š?šÂ›Û(>ÓSj%—È…¤óC¹CÙTnya‡É€éx†ÌwhbÏÚpê•Ú62’îmºGbJjJ‹ûqÕ"‘ÒÔ›äÀìõpÔ¬Ù´µµ!Éö“׌¦&GÃë¢P3Ä™4_°ŠáÓH¬§a“vRMvm{ކ¹.an˵\Ñk¹zô2ÔÛ@ªÛúr‰qÿ¸¶ ‰î½T«[ÍÕwž¶zlrrr`}=¿¨…ÖÔÓp¡áuë›Ðã€;?ÿf ŒÌ R§+lýŸ Ÿÿ-뢦{¥8{Íyäz®¸øßß0tÔ´œ»ËØW²@ëô û>M|ËO6±UæÀCV‰U².èEÑdt5nw£)Ú)¦Z›ßAÕq›©¼·Õ&n/„J¾T§¨‡‚©ÉG{,°T¬›ëŸôAI×ê>Þ|![(°fHj—R•~,ú ^ÙÆÆþéz'-œðóJ=\"š(JäÊ_¯ÐÍM›Ð$©víS1²'"bREb/'”-æžç DHò ! $_L@E>=ú;m\ÓçFg)b€û0 É\6á!-tDô¥Â0|ÈÄI“ÇwÖêоP€1$h×õ9rï“I“ãÔ}"›‰£´xl¾ËŽºS&±Ê$Tƹc@Óá¤;žÊ[ñFxÿ:EQËïúÆgÛ.¨;M ñkT™"øðØ»fNE óÌNG›!ñ)›*ÜÙ.no<1Ç®mY;ò-8)Š"M¼½ è}Oš‹Õ’Ììåµ’µìŽ{ÇV;½`nd°c]ÕC¼šûtyÅbÎYtþ2§WCÎ÷ßé·í^A´x­JñÝÞ»=¼Tô[˜¿böôÇâ~1[ÿëÕÓf±œ‹ÂoóõãbµD%²%±<|®–‹ßÊxºb:_.çóydžµg÷‹Ï«õr1'óõ·ùýüG$†­3ÑßÜ•#ÙB{õ´ž-7"]>n›§ 4ÐZYAkb8Û@³{ÑŸ}ŠÄly'Æ‹Û9µÀl~È&F·›Õ§ùZTãHÄGG F0C¾ÝÏÖØäÓÃ|¹y4ìhuÜj#§×†®ËÍ\<­¿¯çøõ˜?üœ1(îæ›ùú0ô(îVOŸîçâûz~» T=Ìn¿"î¾ÏÖ³,÷(ÛÔÐX­ªvyF`Z,¿?mŠ̽XBFŸÉwèåóºÝ|‹ßf÷Os±Y‰Os±žožÖK<ûòCùŸvÅcñ¾û^¬Öâýü}$ô8þóXÌ¿?z'\ðQ¸?À½¢'\ô“׿§£Î*yÁ%¿g{ß ”ré¥Wzãs±µWl½¼ó ¸àƒß{vDW\òÉo2[²Ï%ï3mÎþðJޏä*Ó&–´Ëþþu¾ž»AÔÈz~ëâ·¹!/Epviš#(ý8û %ËÅÃÓC$Ÿn¿ÁÌ6">àw+ ¡åj#V°¦>߯~·ÁùÀ.é/,h$5Ù«] Àb¡)ÜÈ¡/Ÿp‰B#,Rw‹/ XŽ·ºÜ,gvU˜<ªŠ×>–È‹–w‹å±Ât1Twvw·@&aüXASëß.8µØŒD‚˜ÿñ}µ„Åk˜p¶/ëÙÝÓì¾( õ,Ö²º~ ð®ç_W÷w¢D˜ÙÛ+`%ØAng`=à>_æ›L·!|¯eõÎê íŽÜ6 Z\t3ã>~‹Í4/4ò¥Co/Á+¶º‘­­\§tŽZ ‰JEÆqi,)НU}÷WÀ±%Û¶ºWœõ‘·¦÷Çz¿S¢­õ9éN[–­_ðßtÿNóGtÒšÀºTºK¥»“ˆŠDèèn÷èÏ/ø/¼å†þÈ~Æx-Ù䔚 £1‘˜ÛýŒ;ÜéÓòéxûˆûÀ¯ÚåD÷üzK/“§Or?·ú 4Dœ) ´4Á„ΛÙfŽÛ—i_{³Cø“ˆ`ìÂCÂã÷b7ò‡M¤Ä¤ˆ‘ÔWÌÐñ4žWwÊTŸl«NÐ>ÓÀɶ¬ùÏ«±­>ñ†íõ‡ÛêOŸ©<ÞVÙl@yÕ[qÿ<î®¶vÿ|ýþöþõúÈ«?ÚÞ¿©ïR¡”p¹¨«ïªÕÖ)Õ5Q‡…oôÑÍZV(ê0VìXmJi·ÛÿïÔ‡òa#;X¶pó¬ÖÛZ³¥SXвøcZ¢ ëÎÏŒ:le+#X˜5Ò¦ål= Žl}*K=ׂ¥ßp¯yŽl7P§]‰þ°Ž›ª6 i­¾Ã­Ag¼K¦(@¿´›¸ýºúþÝ-É ͨQeËâ`ý:¡£ Îa ÕsA’Ñ—§ÅÙpd¿Cihã÷¯ R.­é„-oµ~p¬ ˆ‘Ùz±ù 󼸕ÈàU÷Rdh,̾Ÿ£²Àö;P³Ò±a»‘÷T .¡¨eïArüq¯&ûôiM-wæJk”MV8ኺz(±éÆz,ìã•  áÁìþvuÿ ¨w±¼]ÁòXƒtù*ùÔIö‡¢g@É÷ â-i}fëÕo€VX·scPÍ Ê¢U…ø¨™EëþËŠðJxXÏ›£`zÙ ÖVŸ "@™¡ôQú¾Z«±æØÏÃÃcY­…V{,¤‰£ÚQ騮–| œ×eĆVLÊâ„«Å€´]ÐB¦ˆ¬D჊8ÐPÙ´‚¸‰¤Ù(%ÍfùÏÑ_®¥J^º][í3·ëoQQáõI$@=X¿œŽ#RÀàÙz˜†·mŠf bÓú~ß±ú& ¢FŒ:±ù~HYþPô¤±ÃV%ä¸ô8al´XXOžÝŠ{¢(2ä> ¤fÞùLC²>׆ºe»—éWà;_¾ïÖ€%i.ôû\`þ#ìⳜz5}Å|ùø´žgVäýü7B$8$`òõŽö¯óû;d³ëù—Å#nÙ‘»÷`,7ûüy~»asôêûfñ°ø»1„ó§MÚt1ã µ½½ʵv‘Wk#³ø‘„6ãÑ[þ‡O‹ 0ePር, é a”Îäû”m¼÷€Œ©÷]ÃÝ©5¼´µÁño\©Øµ±û½ƒ„íDÞ·õ‹l}C^ßÑ rŒKa€_¯¶NÒ¡`a @ü?A¨ìtpœ;Ðî¼xtÚ5-¹ßZR® N`î ò×Ùýg˜^2U÷3ä€÷³[­"n~_e×f‹à"R.+MéÑ ƒ»ŒÄ¢ ]}=r£HD¦!ØW‘i+­îîP%Cû#(B Ö°×ßójŠž-¿X{80°O ¸U¸MYkH`mRÆÙyvfqšd pÓöúd…íÊÓXͰšò)%—uäS’нUüyRM¢Ò#ÛˆH7j¨îivˆÛÒ÷Ùzãh:÷«/JM%Ÿø^8Ëþëêw˜”µÀ™~$GéËîa{™G|‡òÈ¥ñèë +‚ðüøÌfùÙ–‹HMl•’‹[¢ üuæ¦?Nv¹W /ÕW /üãG@Z{‡o&ØTwÜvÝò§Ü)làxò3[+“¤Ë4¬JåÛ,ã¿Úf™ø6Kr YÞ4ËiöoK¦ÐÓœ¯u3:m¯ïý›°m|À/±{&;Ø=¥™‹t+6–ñø°•{дþmõüÿ‹ÕÝy2|jó±Ýa$þóT0ÞYp?)Qo°Ýö§e| 0(`@R§Ô\îØ  €pŠúç(ãÑ6rF‰ø쌕%`øÒßb‰èÑžšH{ì6”·šFF*K$ñÁ>wRuÐ|âZ$ )v;°p h<÷ÝO³?‚xÒþb9^«Ï!GEùóÌÐHö`%ÅŠŠvÁÝG'ºøy‰© ‘¶ 2ŒÑ±íî3½™aÒp”¶äH®Ëâà µ3ÉåÌãíb ÝªìŸÅbŒòü{Ýw5Ÿ i÷:»à8cTå½­Ï›[º%àf(ÛR#ùÛ 6C÷ZýSl·Å>ï‹}CÈ:=¦ Ÿüþ&é/Óž‰‘Â;§#¼¶J–™ÝUáñ¯²d¿.h ¦ˆþÖäßz åt¹5âqqÌê8NR+οu¨%ĺò†jïå6wETAê°f2Ú俹^Hàð‘ܲÿ*Û½ M4O”5_?ºDÛaÀ¼ß×á\´› `Ûç MÙù3¿­©æÈô,׿ØÜ/­ý†¹_Æpœ:ï–ìc”‘¨þz.LL]\Ì‚ÈÁ ”õ‘@z;`ø9#*Ž'(”úN[ŸÃÜZ¾]êqõ¨_/n¿‘éT&-ÂÂv‹Ø¡ÉZ(ñj½T‰ $HiÂJ „lV›N­È<⟶IÔh*kÛl«ZeÏ¥ªE·cUFrâL['n_Á60I“kBÇåx‚²gߊaû?â1þl/ƒá9£@/Ñ„=p¦IAwˆÐú-îæ¢qÑ–)§™€ùCF7æš0W{¼þ 8ƒ{{uQÜã¾ööcåÌ© èn{EN2EüF|ïÅó¼Ìƒä ²•3­¡EÒv9,²Ý=¬|‡Có²À246ßÐjÜÇ…2:Û ä¯^v/¥øRµX´b>ÌçßA#ýmÁzcKò±YÜoSFH%tܨ»g£N`´·³%®iXÄ(¬3[Ï[¬žEËYÑc¼Ë«×ã2V°ªyÈ„ù,¦Í¬òz5S„(ËY¼‰ÑDäùÆZVU’и=?!"K1)JaŽý.ùEYt,íPV¶Úz¶œl2TLû¶“À¡K:Ú32k¥ë7êE0Á¨Ý} BnöÇJfv4phƒ~_=–˜ÔIF“jl¢Ë•Dhhð¿<%^ÌË_ʰß~t#Â…¯)‡TJ8éJ†À%•wßD3èeÒ‹Eä]‡Eý€¸¸¼›­ï@1½¿G;ûc`¤y ¡Jø·Ämÿ þm¹úÝœÎËä`4xÇ‹g\vg K,ŠÜ˜þv 7Ú9‡j*‡z*ãg¦/÷ÐP}Lß‚Û7˜â,©Ô_;?yÐý´ »4U}gw^¡–`p´»­Èà4šºã|îºüžAô?õŒz‚Y.TÚ’…qwó S ¡³†Âq´N¶ø,>¶÷ ¿€èÏýænRÜr€(´–šEÈõ8‚܈Äé‹Á¤^ëšå~||zà¨X;¢Do&¹ÈÑLfT4­ißöìˆ8V,È]PÉjtxJ­8Þwr°Ãö¥Ö™ÜÅR뮬˕aV6ë' ¤šéïýŠ–ŽO+ nDñò‹I uþK¹t#ñyöt¿ùa–Úö©6ÆHÛ'uåÞòèOy4.+'`(VÔz'ŸnoˆÐ¶Š‚&yÒà1Û:Å5êyäqçz¦!ª?{ šŸÉ}OÚ¤€Pï(TÈVá°,©ë3óÒ°ŒvF²éz¤cÕRr"ýΊ˜žÙÂÒéb9»¿ÿŒ|/-aU$±G6e¶l´~ÉQëë®ZÏÖ)6Š*‹•sFîg¿¬¯ô­“PŒ=/}ûÈ Kë[§hdÊpOã]ȼ`9qlÔñ^ H‡ge2w³¹œzG²ý4ç€q4ügé½k”{¯Á|È9ŒÄ÷:ý ºÒç †9,ѷȇ¥7n7÷«Õ·ÇLË3 ìïldƒ-}…·óŠã((âþTr½.ºõ7Ô—¸X¥Íãn.ÊášÏtÉnÒÆ‚íéãܰȾ¿ÿÁÀÎÿø~¿¸]lœ±ñØnùäÏvË?“[à cü¿ÍŸã/x‰¯¼J:7FÐ,ï8† ÂöÀáÓ'Bž÷–ÊïëÅŠãwV’="Á)/ùLU`±èCS)P&Œ÷iÆvxvlÃ%¶ó°øòu#è>íäJâš3mÝÁ-Oô Lfç|wÒËqe'’[êYKºœc€c§ÐggÙ¥Wý«#bj¶A‰Óùœùÿ /Ü"SlsæÞ^²:k¸8g õ­CèBqM1÷Ýa9d" ºžñä…a‘ XpÝØó ù¥QàÔú@ª¬‚hD‚a“ kÅs‚JfK²áSŠ2ùÍïä0¹ÕÝWö#z"L(¢M Çø´kÜ=ìa7-¿4’çÍùEŽ;@xéöÍèú$‰zLaÇôœ&ŽÓøï~†5j‚’¿]¡kôµ¸{ŽÆ®+¡ŸØ¸­¬Ð ŸvL†uù#±~tì7~Ã&|í=i«€\é;µjýæÑ+ HtKwTi.`;[²·uؽ™ˆïÄÒqËX"¡ÝŸ¯$K´)µÉ¼ ¯õÛE¨œ £ ©Ú³ï…K‚3pS½›ÇBU臂`Ê3ËŸ$ÏN»šl d‚É-ràLBpV·ÀI-'gÐít9ÏS三²>¢-RBí¯–ê*nöBEy²2ùïhÙà¹ÿ-E&\ö"Ÿû²,¡ØA²¨‹ÙXí÷Í£m/ยЦ,CîQfl†mVì„@EUEÒñÉ™À9ð¡Ë7Ï>=p EÐ3é`Ûìû÷õêÅ0}Ð:1ç ÿãd&ÜÎï‹û{ñyƒIô§Ô‡tR_ßIýÐiÖPˆhÇŸÿ1CÓ-«ý'ÍêÉØJÉa#©G:–ðX$‡Íø°hu?»\1 ‹Ï–JOÊ2Fc/ÒòHúÐjÅèi¡àïÛûÕ#…´âá“b„¡¶Ÿ`ÇûÁ6dºÄï&¨äŸ@—4"ë<Óœ‰?¦† ˆp2ú°«{c\·wþÙÔÊs`7ˆ~ná‘•ÊXŸïg_d8ø” 3¡$s m޼ûÒ3Á(¡ZIjZUfíu{aÌêó)í°Æ«cUÃK[ÎõŸ$Öî˜ñwÔÈòÔ3ÞY9î*‘•ÿîEùî|·ûËI:۰_.&WŽï„ï°•ðóéø6x’ÿ¨ß¹ÁHÛ°ÿG¾þí(_¿4r0ê¼LJç2§‹5•ÚIc´…^ê6¿¯˜µSÒ‰„·…OèõõÞ@¶ü †~𒳃c–Ûˆì$t#Ò‘ÚGfÁ´HMg²zÚ—cz¹IEo=ÿß§ÅÚD»Ó½–F;¡‘½‚©G=ÈÊëxµÛ1UÒš£1}rA”ºaï§ìÊY²¹êK~qŒ…%HÓ#6ˆB¿êÐíë2wÝW/Gû ÝwT¢Êéì/íÅÍúÑ— SÄPéJü²žÃôªXÈ`²êZN¥µoá^µœÏÙÈ)Û “¦3çndk†¹Ï µƒ7GÌ1èØ{.â¬2ñ$ ù¹ÆÓ¤‘Gì ª*Rr‰÷V<žnF$ÅÙö¾¯Ò Ýâ+5fÎl¼nVè3»¯J ÈÝ_lDÓ)(›xáòÐ>K Ö-7XwA;ö†¤BŒEÒ¸»ó|z —a$Ï-Ð)x¿u´ 8ò~â“F–Ÿeê@ Dëù÷õüfM‡áI'¯Õ.'6¼·=¾ ÿíõÌ8U‹B"‘2l†!.ØCC)ý&l¿.ôٙߊ³?L£6óõ×ÙwšYÓÊà x%›X2yu‘w*®,lÏîiÃC/VôRúÙÄடXø¦`>$Nœt÷t+”¼Ä3ØÄÑ šÆù|xz$c áOƒ¡_K!6©ÉI`0Rr|³ V#KƒÀ‘š#„ i† b³ †É´ñ "úŸA¼ÿáxRÕ²âu—áx†ÈiF²Ä+ƒ$+‡ã”çyÂñ®Ã`ö¥á c¨Àò3ˆÊ>¸?œ _¦aÌ·Äf·¨‚îòàY¦Ió㟇Õ‹£Ţؓ¿ˆ<ÉÁ¯†ù6pZn=ŸŸîy?7¤ xyºß¸ 6aÏb˜±G5^ëBºLÉ’5o\‹Žcvº0ø¤+aö¸móçù#u­CØÒʇ2!Ô±öËËÈ„2¢( ˜øn0ª×(ÖÇVé{l,P‘!¸Û0!_æ/À1UYŽu¶=6E8 V8‚D3ØÆz®Iªî˜¤ø[Æ:¢Ý¼*E&Ðþ—÷óNæß‘ñ¨BÆ£ÚnÆ£Ð% „m>„D}DžZÀ¸[jK½ –ÐC`{T¯ç_@g¥UÅhn1­Îó&ж<|”s³Bûdëk3kH{úŽI7à4eÎàhpï:jJažàEC”ìváj’©|âW>q*Ÿp宬÷Œ¬QT«>RG!U‚'%+²À[¡%NŽ|¼T›©#<˜òµº_¾^ÝV¾‘øåiÜ6Þ÷E£Æ»ÝÉVèN2Ðl…î$݉žX‚nËÄÆ‡ÞÄ&õÊÔVrî0ÍP’ú89 Ìý®Sž$þ2Ä»-§ö‰SÛ] a¶ÙG±yê0……5ŽÂ›¼ëÂ’×þãߟâPß׃‡ù§»Ï‹òç?© |µým6êÎßJ­Ò¬&ñÄð'®Tëµjò•¸'•ÿ•? çó„A?BüÇôëêaö˜_î¹÷þè¿ÿ"Ÿ[º#¸Ø {Ò9MÅðjУnÕÇÛ=û»Ñ…‹Ñd’žà£izzZ|w+&7“iw€—ò¡ˆÊ¸"éhÜI‡­ñè@±î¸ JhiÝË«*gGch°Ÿ»­1´gî–lußÝÂëöêû5…vÚEÐn+Mq>ÿüYËn±ŠÂ¯e$ÚÿwñÜs1»/ÏnËOß"ø% ú¾^}YÏÈÓöy=GKÐçÍï Kþ—ø±z"É$ÿÅ#ˆèŸÐ€Âh°ߊ‡Õªðˆ|„l¼œ¯•qÿlx…9¶çkË/ž>݃ˆßÍm :Ô-êAßñÙãW>hN‚‰„@œ¢‹t¿ÿRÛÖ>¡Ù‰l‘̇Yì5¿®–E€õ‡¸GöªY&´ù#7Ô&Ư«ï:c(;D>QZ‚ÏO÷´€‡®Óiot5­á ¿[ÃéÍi—=æJ¤–Èn†!ä³5j¸hcƒ€nð¢Éië$í§Ó„þ4»“ †Õä_´ÆÓ´}…7±^\¤º˜³oNÖA¨Ÿ[R(©çç¥á1Ë·wr²¦[ç'¦2B!4ƒÛÔ×Íæûüþûïå/˧òjýåàž+=,–ŸWgýß’ÕºOu¾nî©û &ûÌz~;ýÓÞïF2÷+ô!³û×Ìà¡:´\m"ñûz±ÑÉ­b‚Ú†œ@÷[Þ–#Q¡Ðlùíæ|²âÐÄéâ34z¿Z­#q²zÜ`ñhÝ•$Ž+¥¸Z‰qþ¯&-‰!·o+T‡™CaM+QoÝT¢›‹q:èFS(Ma£§QÚI;QŸô¯GãòŸU§ý”þ𿃬ÕúøF”NGýhŒÿ´èJ”â?vPòc4îN —´;qä· QzË–pÄ0u¾-cZ>/‹Ö§»§û{NÇ{^–ü,â²9æÈ|nÄê®0±·ò}*¹°Çûûù—¹|Ü_-'×M‘´þÆÏºË/÷x£Á-ÿÜ”gÜïÿ *4ñJAÅ„â£ò©*«hö ~-~'Úþ¤Î™HC<9±!yîäQR }¾¬VwØü§ÙÝÿóÿüsμ*wÜýȾò^:™ŽÆ7ÿ)ì[|ñsÞ^á^–T`ýÀNÔøO¿Ú£ñ¸Ûžv;¼™öºí’ãM®NOawêÍ}Ѱe†ÛÁÚã.ì—¸<&­v·.8hÁ~=¹¢«„»âckœ¶ÈýßïŸBít{Šoú·n'Ü‚¼‰ø¤‹7iãÝÄ9=»%¼©†¨HÔ!lüh{w;Wí¼^&é°ÝUÜòØÝi+íÔÑÃH£vû ‡]ûÕGíé4WãÇ b¾šþXÈ`çꈋkëÚp¤ÑÀ`ÌA”8o8š:• ì“. ¡ÛÇ[ÐZS¯¤_mÒ½!‰f ÅGGGÿ)å¥q·ßÅhO5öÑÇÎ8ý¨ZÀͲý¡uÖ%Bb¬úWSI?ø[‚./™¾`@Uk±„6Áò–˜eËe­þY÷dÜJÛFB“kù¬°‰n¢›÷ÅãJ$nŽ 7…¸Ýü§ZŒÊø¯CLëÁ=Z›…JŠ’#~ƒá«W]-‡˜{þŒ»f»;Ñ%b€"ãlMz‘D´{6n)¼tÆÌÄê'…ÂåN¹[žÀdã Œ/)ÐÊ ;H H@aØ‹Õ ža¦á½çe"½AkÚ›”IŽÂëèçØ•"ѨÕKz3ÂëW«k I‰Z€Úm˜ØJ1ä¾5ä­—EtšU¢3–Ð`#¼qELA€›L@=§S4×’R\?Œ¬6 –ªaªÚ0Ñéd.Àá®Æâ­ÑI±~:ÂÙ°ZÔZ„C¶<=’.Dàc ¾ à “/¦9ÒPÔŠV¹]ö<ì Zcp€tƒ¹¯¹‘oUoúýn[õ¶oi0cè å!bÄ0Ïmš0$ȳÈ 0Ž ŠÅoD¸·¹aa~÷XÃÕzóµÔƒÝöV`UÆÖ ß¿×ajkŸÚ: Ü^+w™/a´†Ã.^ p!áõ%«s£9¥i$ñ‡MÙÅKfëé·Q‚ÚÝ0É wöe.’FÓ¬¼ÒO~\–5œtéÈ0Ìη$Ü.^Kl/‰’¸â¡°,Ѧû¡‹;ËE,5¤H ÷Z³êÕr0caž€]è@àBP¥¬¦…BHÅ12E欕Ø)±aÝU50­X ¸«ÄÏT‘“ §z·ñ]7ÀhÁ#ÞXoQîlh;© Þ}¡’lñËöšóû˶~£†Òaýîð Ö÷\¶­@g‡J»Jf‹Í&Ð3iâ•=ûývn:S5=¨¿*Œ™i­)‚0$tÚMäÂkFþ±w–ë´ßÑ`< «ÈÙHLúéYo ßOº7#XŽØ©ß.S„AmäÔ¶ šo›(câL]Ü{vü+·y`ág4 ìàÔ¢ öÞ°ßo!ëœWEúœ'q”$QB’XRƒ±g€í÷G× ŠaK“.­˜—l…L_r?”{*˰¢d¼m [ý›)°*€DoYÁ»=:I#))ð!L.ÏìöoÊô¸zƒAXY@BÓ³?.¶=$ñ4€ÔÍ G×0@gYp3@Ãc¿™a·Û!„¤§7¶´CZ)°'@ ÃU5A¨Ó iYØ‹\ör@£À,p'ei~zsAÓ«%C”1ÁˆþÄcR²Ò@¦jŪŠRn°: f\?$•!EÛË‚Y½Šìð{,Å»ô¨ŽòzTs;)n “.Hé°m£™@± GåˆT2ÃN„ Â@J¨M·A"‡&[SfØ&oW½4³‚ñÓý¥ÕÆ…^ެÅ+Gß »Å æÔšL€¸'Ü úax9 ¾+2Ëmª!0³ãQ_ºZÙ€9X\¡.01Ñ:ŸŒýÁ­¢Ì à,œëv"qóÕmø±çwŒ[¶ —™]i=Å v2‘/C É©%,®7quÉÒ à|ôÀ3U„œÀ "Yå¤Ý’øuFâ % è¨dÆ„ëœhõ¤+I ©T¶$ ÝáÀÎp-â–ÒŠÔ~R)3cßÇ1Q5´›áUÀUÚ ðLN¯ú¼Í[M(TXí”§½« #'2CtAŠÑ&¨Þ@³«Âļ©{µBÉSšÏÑuj8¤b¤•¨ )¨ŠôÝ:}ÔÜ¢OÛµä*ªKÎZ“‡]æ°˜&¸‹"ÕaJµž ™Á7G{õ N±1µÔ¨.mŒÃîõW/Pdpmiœþ‚ÓÛBzÊ|L¾Bž1èC/­³ìf™)8éÂ^Ê[21ºë‡W¦#"´ÝzˆßŒå :9¦×ÊlŸô.¡wWÁwU~'öqv*T+RÔ9• ²ª›l•ÔÑú%\ ¤äLH·t_Nˆ6õ:”åÚ0ŰÞãÁÒk–ýÍo€+ƒ&: X6¹öÑ¿‡ħÝd†kÑv3ÎÊ ,L  þÑŽ ¥5¡DÍ2bψËqV3Æ©1ÐÕ¤7ºêwOM ñiK¦¥ÍhhÏfÉz¨¶w–qí-¾;ÃCÉåA ífÀ µ=N/ˆï1Y] k¸ï©®Æº+´)µP>’-à rä‡ZB¥›Ýñ#Zþ ë¯5&'µ¢”dŽþšn×+LüY([ JD@넸¹‚ódt5Ì ƒªù xȸœ¨Õ¾€(jÁÁ±¸èŽQJE¡öFí*+!jãw,·«ˆ„Ya™Ãh ó¢X¤¹Et± dpÈÑ "°¢Õn“Ú†ì’èuL¢DI cp?LJ¸a9êú`þû† ÀÀŽì:&ýaËkÐ…~&Ð˘÷Å€àtPøˆ‹r9ž xúã7èdo/)à+ZXB(„ YÿŒnwÝEi"××à*»ÿ´ú×­\Äâb4I‘Œ#-ÿÓ™úÌŒéE9 KÃî­)°Œú´Òn…[HŸ$ž¿%5 ã¥ÓÌ &‚L‹LÐÉÒˆÿÃfѳØ/!öKöå^*‘ƒ­ÚÊN [«ˆÉH+KYíÖ}nñ °´‚"fÓ§‚åLºyÕŠ ˆz$6šÆB­g8Ì&®[A¶h‰ÓÖ8,7ä²¶îé”Ù5€Oͳš¸;{¬  Ç̯‰6ŽC€›ƒ‘cXk¨ôó°3ìËú0!Ëfa«Ý#ˆÅ<ð`gc´X%9äu ^oV÷¸°ð|áZ4ûbÆÏ‚âå•tâd‘=K?Jq7”‰(0ï> ®iÁ_;fq‘ûjr¢=¶}*ù CTˆ•Ë}?-ýmK-ÒÄÔöbC,X( Á6ªn¼?å·‘JÍ©ì‚âLÈPên(6„#wafû“®³Ó!ÿdÈ"¥šd̬©hy—Y„Z#ï'J]TŠ˜¶‚H‚Ú¹»Ô8ÆÈàÔéþ"@rª®íÅj%‰ðߪ°ìF¸  òñ£×F…jVM¦ÝY›·qG ±tOSÇd¤¥8HVTÀâòîvºVáÄzË[NšYŠdkÎV­šªZĺ I¸@"!­¶„Ú¬9+Œ¬ŸL“Ì´+ “Ä0m0E‘öj(*xçª5—™MÁZ½šÙ?ÀF)c¥ÒC!'©þ‚D6Ô#AÓ¡ÂÖDíÇ$› £¥CN>S‘V¬²íÿ›¸0ðžÜêO³š#Á@FbX h±à…0ÝadB6ÞCý>lå ^H å^ÀÔGï³$öà%” É|ŒgZ¡·aFul| <¶löœ'h‚}t¬â$Fcl¡gtàRŒcì¡Z<éÑt(Áø”w cænÓK)ÁΖVþÙaôB,\¾“­Ø¶ Ë´)­ŸSŽí’ µ|FÄŒ,zV‚Ð|çF›È a›'[¤©³•Ú©m,0|Iñ»@ƒ–µ•&b[?Xý¸Z®§GÚ \Wöô8ŽËÀNºR×ø•¤iN™™ü©½Á*7•BÐ3£#"z¼¢û-¼Ïéº×¥¡™Q ;íIÚnucèå<ËÅB†.×KÀ¾“ü:ä ¡zǶ‰L;F®†<]ÀxÆ#PPæj™kº>³µDºm·êºêãQlœòí¢‹1ø‘R&e+Ñáx^`Uãû] ¯ù¶HãÄŒ…RÝÚ=\¸¹Ì0E*^hHò×°T›QÄí~Ä5O•(ÄkõP hA#R©±«Æån\±jɺ”‰^ñˆ¢ŠI ÉÆ4\»â¼Œ\2'7ÆIj®£lMŽ®ÅP ‘í€ôs$Œl¿°$ZÈ_Zí²pQ˜ JËPÃŽÑ)U_ˆèV»‡V0ÅŠ9ðÜ3 ôØ‚r»®Æþ®(Ga/€ÎŸ"©"”0¶v ‚(äȽÅ,Z v†½Hó:Ôq¨Ò&iõUW $©öÇHûž”Ï‘— ïÌ´¹g—´Å)…îtAÀÃà¾Ñ»caÝ‘eá9+,.âÓ”±‰@#XÔÝuˆ@( íŽÕ\n.f7ñy¾Ü©º×ÊX¯ÕBë¤ä{$Æ¢6qs•B/PͶ7ë-[J¼åI1´V¤ÎU÷MÞŠbÃ%ÀîŒ>Oæ«1§Šq¥R¤úšßÄά?7tOo—ÖP,n•øµ›}¶ÅŸa¦:”0h`»@7òØ­ÉP&Q‘l¦Ë?mqa&‚(Q>I×y3gÝ©½ùò ªHz âEJäw ÊŽoXBÖdÉ¡:UN?ÜCާLÞI¹“¬SR§1ò!N&£vjqKeyÕ2Œ¾ãÖÓUÄŽä]}á @dÙîDû 丽1©î/ìÞÕ¾Î;%LnRÛ΃Aé«èœ€ä¶/ ñA¡Gçò‹Ezö^ÖêtÛ¦S £Cѿ—YãpãGÞÀíê9õ­Úò¸ŸíÐᇭ=<ç"9;4„Wo92lH¿‡šáÎÙÉiK¨>y/ 0C?Ö‰ŒÆÃÊ'áXPÃi¹ó ùI_7¯¿°'ÈŒëãO9á‹­>诓+ ‘C¾*uOúèÁ–+2§æÝìï?"q÷x;»Äânö0û~Þ­66Û²ÈÙ›­û–vnbŒ9^VËl ³Óoy+P9à _ …®0n¢‹N4T'¤³(‚ÕÄ!û¼ñùÙ€Xë£)œhzo˜¡k9}[š`}ƒv}-ýHzÞà<&ߨ½|q0×hE†`Û]Øõ×ÊS±>vL‰²1І„$tÃGLÙ»µ¥K…” ÷Õ`€qT2ŠÀ hK;ƉÁí<£ÐÞ B9vRö6ìÔ */ÊÚÍÌ‘Ø>(¹~ÈõC=_ #Bq–´²Æ–F¶tÀEÐh!Îɾ­¹@H– OBʳ¥<±CÌíX^GL• ë#MiØûMá¼hj“clÁ¢ õðò&»îãm˜Ø:xg„Û¡;v„†¿li…Bò†8‡‹Ò¯ûOûqô+àFWML4)‹¶‘,ù 0Þ°KVëtbV’µÀ¶-rÑJ¦WŽDbŒ}˜ˆY›/[èåÚ^" ufvkµ¯á.¥È_–—«%‡O©*žRöàQ‚š0# :^9Ó¿ °èô£1RÄŠ®mU6v»¾;.ƒ:ˆ…GÂ`î;Ýþ´¥voØ‚cw ÑÚÈž±mõ¨?˜å3ÚŽ€òìÝ‘evá†Ê]z(èÅHÆP›Ø¯°ßÌ|dƒ2ÅQ¯ð¾ûýqq¿Z¾WcMV¯@{Éãÿ®7Jk0¸ê‘õDŽIIÈGAV"£†8V"*.÷n#**Ãû%½.³rS£Ö¨1ŽÂÈ´¤ê‘(¬ëÕ©žÑ¹¼è#@Nëƒvê©&P±7M4¼&ð-ﱺª1æÜº²FÓ«¡ç¼‹Š„tx}ž;-z-h¶¹¥k¬޼|I7SÃLõ¸âÕZ ‹ïýª(Õ[Uc¯ê4„‰*²¥lØ¡F(gHSjìn_¤À˜¾’`_¤ºñYmæó2:—HªX,•K‹¡Ó!0 ïÕV©ÃlT5Í5•dë´·ª±ÉôÂ4VË4&c”mŠ%2ÅAË¥²e ¬W$Ç0¢2$󏔨¤AA…zh‹XjEÔ;ÇŒ›iª"Ìl#ÄiÊœ–kN0óÓ™xߢð¥÷òÄЇ®¶ɘ¥wïnß©L=úà–§áZ¥^4*ýM± ÿyÕGïi((Ñ3˜ð\>©íárÏlp:¥s„±ˆó'_ò;zË蛩htbXÿ]ÏɃ.ÁÿûUŸw²6fMcook|v5 ½>“W‹1ó!eë4óà”ë¼²nÒ´ÍÒm i#0J Ôb1º©†ÅHÐÑgü‹[ga¯Hû(üµ@ÃGî²PÑ›[N¹i%V ä$ÆChøq”‚œPÒZ”Ö£´¥Í(=ŒÒ£(+ðå‰EŸ%ªÚÐÞ‡I uÚö êîô[6]EÖéî@[(¼`ÈÞ”L¡¦z¾;Èf°§¢€óL©üļørˆ!U•À tѧ(aU(â]:+­Ÿ5ç©•YÓ¿'5=™“@&Õ¢šµc¯M¼®d¸'ûÞ­ã)Þ’b^|ë¾ÂÛÁÒ„^yojø¦ŠoÜçu|^Ë>oàózöyŸ7²Ïñy3ûüŸfŸÇ|q„D®…a¯DLã¬ä–Ø"¢ÙÅdP”ã ÎK)ÅÉÀ7Y´˜3‚É„2N^`,áöž!ah"Žý7.5U€šp¬ÎÍ9‚Îé¬Ly€¤ ’á~\{Œd;15´âà rð_ºk‰@ÍÊ´QN-•yÀW¬X'°ê§‘°Dw¥˜H)¢PE‚Oö$‘•ì'|ùM¸yu•Õ6¦÷lû„L;"G…‘ xY”„ÝŠ5¥( ë >Êßz;'W 3¼Ý“i%V‹™t@rE~™&êKU}©©/uõ¥j¡©Þª/Gê PA$…±º[•2wèŸTê4ò @°%©‡Ý é‰NR©ÏDJA‰”š)íÁm@*‘’ë#-¡GZàŽ´8i95ÐJ¬¦p å™!H-ö§ä¬€ÌEȉʰo,º,=iíñhà‡o‘¸éúù~ åOþ…ŠC­”RÌ1ü†7d0_ùS;ð×Ö¸Ç_.® šÃª–8¡‚õ\ ÚÒr%-£ ~¾H•[‚Ec½³•J’s¥:^U’©¼ÈAå¾¢pDï9mˆ\šüÝö-J§5ÚËèœÍûk¹×{žuß¿GKÜrà<â}°²Ë[2¦¢÷(©¼¹ ËBc4<Ãm ùðŸ6˜¬»ñ-ÇÓ'ùÇcûñùÔ–VM”áö1¹2eòÎÀ:­Œ†íŸ=0oϦZzéîp㌆ØCÄl!2&À‰c¤uÁ’.®#^Ücyœ˜0BfaÂPÝIoä„¢PŒ&æV±cV……ÄoÞ2TóÐ#qכЫîI…‰P缘VTL¦ý´‡ŒõœGZ4Q©ó¸ Š ö“ ö%ÚQ ²7H *ÃxbÔUzéÔˆaÜ>{á‰(L÷{E3Óüɸîò|´ú$œ;/豺æ,NNØHΕN2êmqP*ç‰ß£ÙƳ˜ ¼X‹kìñα‡¸(†#~мÄË)LäÑ’’“ØB“"@mBÚ›¼1R`7GÀR<íÐÊ-Cr‡–Þ)¿@g~3þ+‹Å{™6á}fHxD‹”`&éΘ”RÍž› ~‰d·øiƒDf½•bŸ Pw±NòŸ¸æUh­)œ¡‘½z =´t°Lr È.ÏŒXhDGq#ÌtJÍ#±hÏ_ì¯ç§>!º¦¡ClI٥̗~€¸Ã A¡£þ _õͪA²y†ûVý‰z+´Fÿj›’µaw&D,–Á[’Є²ÈpVLŽRb/ð¢8gÊ%¢BQl8¦ ‡ÝrfÁ áe÷À,…[(¹‰¶V(þœñÞÅ |†ÃcÇWP@)· ž¡}g¼ Ý-é1¨PžADBwZ$ÃheÕÚÐ ŸßnÑ­e·°ŸBñÍXÍ›º·é¹ñ£wcõ#±Ô3Ç.^’<¼´^€/“€ÎxĆFF=ˆŒã,*‰‰ðÐñŽ©F¥h èm°º€æì .uÚÛ€ÉZ'vQå“—àÚBŸà˽xF2¸1ÃLÂ~«eR žG3ƒnÃxeÃÆ»KÃé çxB §/€¸þš†Cg\;‚PN­2O‚àÏV‚‘­Wºé»jžd‰œË¸¬ØñngWîùb“f63ͪê;½ÈU˜VÔ¾<Úº1[Ò§*4 PË1l0O`{ÂÁ).Ì8r õ3qVÝŸµ¢°­4€[†pˆœ¾br³›ZÌÔÃúN´àåbQÓf0}œe€lzÓ ÊŸd3£Zg‘gÇ-åòå8Ù•/;€‘-Uî |ßÛGùXþ>¬—«©@ mØ'œÈÃ9¬¯ƒ’ä)v+J9 ;o0ÛE1» _O™Ø›HìsÏ^ÆÖQùC™•måGÅ‚ã/½xÄ›‡] ^ÄTºsSnòôÔ>aKéWè<%ú‚Õ3áˆPNe„ ¨ÓÔ>è7š±Fo•)dVe7QΕҦì/K@f4Õ ú‹W©’_ õa:”GŽ^1² õ€A¨³‡ ¤Re×H`‹2á­%YuùghR#–¦›Jh³3åŽyw”¿"4 -Æ»lv7¡ A«‡e—›BÅÅc‚æ–ÚÚ4‘tÅ"_ÁÇG8Or˜½‘§ÕÚ66ØØ€MXÚ©û˜lÞîÓ!dbUÞ $=ÏòõØðL&hÇæ=8eï’ÙØDÖÑ4µ^7Ê6´ëlwo×ûÄìŠìC¹ºØo³ûM$?å×zÞ­%ZìÝrBèq™Âo佞dã°u¡äsÉŽÛz¦ôD}8Ñ1‰’cI@ €76#°,cv6 :ÓÉÙè5…œá}Q­d ,²ÉŒu»MŒ‰v>&nBqÍY>²H"™z°/´{£ ^‹é©2CßO))+¾VBÏ>t\èª>t,°Hˆ(î «­BЂ¯sdÑ2~ä,œ˜Lh=®f.\µç±fŸ£7èÊ ŠlA‹’úªa1ÊöO'Š—.ïêÆ2FÍc³ï½xn~ˆòæE2¥d5¨på+õrŽ]Dª×uxpº°¼×™uÚ1uد½r²~?´¢—ý¡2lÕ\ VŸÃ`Káì|Ææ€€²ÙÑCÔ2È‘®Î[ædÑ”¤¾R68­ÕŸ©Ö V«?×ÛPÖ1UÏU±¼‡|_Ýaó¹Ú¼¸ÞãÙSUç0SGgÅÓw?‘°c»cV¦Ø¼&zf3Γžù™­íª¹˜-¬dœðÏM÷ê\%-4¹Õu¥÷R¹žžÃ–墌Äà4’g,¶œËPGÿ-s„¼j+‘$gþ¨Q[]Œ2¿bŠÊ3HxÇôér"¶ ¡­,G²*‹3œ,ëaDØTÈ2•K²#¾P•ÌZ÷Ó!p¢Ä‰òeššþ"=iu$ºÇeò’€Kqz_7è¯C•R/_ÀlÑvžM+³Š±—Íá¦H„û‹4˜¡ñ½9ãñÆyf³V[í®Iv:J"»ê:/;8âœüxÍÙ‹ó(tf%猄w ÇKèËYq@–Ť,¸/Ô剥±(Éf‚‡ÁcÛ\„ÁKqNVP+rƒ NbPõ&û˜˜ÂiÔšÎKI±XL},Ýkh2u›Jü¦èJh÷™é¥I%,kÖøHçGLLÔá|±çW“©º›Ópס *åL²/Ó1¬t~Nò*e]Ø›0ï¡r.ºãéd*“ºÚ7*1ˆD!þRœ€Ö-ø†\”@!ôjxéTt¦³ÃqtKKÌ æ¿Å4>­¶',m“¶N¥ñ‘(“w•©Ë¾ðѬØ;YVqéä?CpàfÉ- /Kq”ÿ2z®ö~üFÖ—ì.ÃËWî+Ý>«Gò¤/ÓËBýûˇÜ*2eP¨ožøÂaT õøÜÖ´ë=‡;ªSòbíͱ!Å Èv¸ƒ¸|Éß þNÌï*þ®•ëžÈ)ßÖðm³\­Vu…:5X)×ý¨Aªåf¸‘&½n–㺮qHPTÊÍÚAèÄ2Áߤ†:Ñp…áN| ëôˆ€Ô`'®0܉ÒÀjåZ#îª g‚\üUñ‘- zÕƒ³NOü5ð‘- zUÁYÔŠ„`SÒÛ-v7a„Ãcì|¾|›0HeJмд“ŽuúOv‚*Õö…S>] ÞŒUÉ%‡†ËKé¦DYD%“;FÅed>»cõŘÙ2\(J*QµÕ*Q½5*žé€úX DLäXE_TdþÅëÞcº³T±ŸsW‡lML›rÃú4;¥J¬[âvªH„æã”P •ëz7«¨×Õ2e¨¤¬ßך‡‰_†®é,Åe»LÃ*ä  jP/×êæ¿z`°¬ì"n‰cð0¶þ ±Ynĵ$®ÆGÍ£ÆQ=8Äj99:ª%ÕÃzó°‘i‡ú:,7’£Z-n$µj£^ƒ2‰]¦Nh8*ÇÕf¥^?¬6ëª]ÈACÍ ØÂ¡M @â<­ñÓÄ-[ç§q"¯F¹Þ¬4:Î_xnkåJ%©¡­zX È´yTm&õ¤qtxä—©s;µêa’Ôšq%ŽëG>r„œz¹Yo6`’8©Æõ<äÔ rjåjó¨ÞH€¬ðo€Fêeýÿ6DRØ £*ÿu‹ÔyˆGÍÊa%9Šù¯[¤ÁÓ߬ÅI­rH«þ%MÅñÈQ܌뙥"Q^;ª¦ªÕz#NÂË)A2ª×’fµÒ¬5*A”•+@Ö&°Y;Œë• H nªQ«%ÍF³Çͦ_¦I3dL nB‡ ÌQÞÌ4왩ÆjÒ¨Nã¤œš£ø°ÚhVk€úÃf-85‡Íf½W`î ½j`j’2o¥Ò€Yi&q¥˜š0Ú¨6ªGÀHš^‘&¯Yÿð°V­W3«Wq¤Z³~ØlTj1LcÎìÖ“z:¬6*^Wfö€‹5ë`:Õ83Ã’âà]µYÅÖ+™n0<0k°taê‡Ipê€ïB@¶ X€‡±_榷 «x`Z‹¹ÓÛ4Ó ¥kGÕ8¦× ­¼F9®U“:ÌÌ!p¼$Lo­œÄ5ÄgµZ”„§÷(±þ Î.Ln\©7`À:ªÙËñ¬`wÀZ*‰ËÆõr½rԨŇHá‡D¯!¨ÁŠK ¹j-HuXš5àïGGÕzrçðKØ ¸ëT3D" ¶íZh2ý"Ã%Ï9jBGµ¤ZϬï&ÏÔQVîQ (»ÒÈpÞCî+©TÑ#P…u˜d鈈$)øê‡$9ªÄf;¬ 5ê¨">5ÊdõëV”Â&¨›È E=“””ÛÊ5{ð3qŒ_ÃKmûÂø±Ku²õ»cÝ|)&Ë}¶;¶,à¶ „hÄÊÚ°èN+øͯn4Þ:A)ß3åò´ëå$âÄ)GnÛ­à“ªL~y¯Ú7îÅŠËÈnŒüw]P0¸R#ˆ“Æ@“>¾&ê¶¡SûŽp/ DE4IV©{æ/püÜOë¢ûU¢¡‘)_Šóc9ÊýXÝN唨<Áûç6LÖÓwØžõ1n=KèQÔ¡tö[}«õ*3ÿMe në08ÓŸn´Ð©ñÇ‘ówÐ6”²ëXóɦ’rè_µ¢9°¥ŠãeÇô¯!l‚÷- «ÂŸu k³.cAihĶÀÕ`¦¶t¶gÉ…h娢”¬‹•ñéÐÈ3Ðl¹®Ì…)Ldétpr¬)ħÌd'âÃqA3.Ñ󒬋c5tg†›ÔðÈMÁh{þg~»e–чž9EûLîuÔ‚ýú{’ÅïKï®âgó}lk,Í6¶5ÅG¨­4°­Y=¶µåÀ%C1«õì e¸äœn¡¼!(TËÝ0-î©,Åâæñ¯Àí£5 š+äíéÌÿ-òuŠªÃqE£é÷:{Ã=_-î9éñ¡ýq…¶¾Nçß©„èçjQ1å]&$Y ¤Ujß ÅšWø)M¶ãî1üß"Ù‡}¸Ñ&çjrÙ3}sq,qz^TÏ‚tLj ±ô¼ÇGÎAv©ðôœkz-zÔµk;²—žìMdì£EƒÔ£ÂÛ#–Ã5ߣ®&ò?µ'H*¾93”©Ÿ å0xœ´ç.sÅØüñ †üH3-–Xêôs H®‰Máð¹âÁØ+£ß»å­ÑúG¡òñaP}F±yJká<æ{.Baûx'Ö1ý EL¸»bܼT¼:/Z0~?zÅ NðÖ´‡Å²ÂÙÜ«ÅH ܸšbØ¿pßj970‰Ù9æ5æJžYÔw⻼·UbŸŠ£¹Ì5=Tz>Ep%¥ÖŠLƒ+RåöÖ÷uÛÈä P‰&èϾKˆzä¼ßfiv3"äËÖŸ+ºà4žçÎ.„•çíü¼óÔe @Ó² oÎÄ«&íÜá£aFú’i;·ùéù³GWë@Ù . ®2£Â vé_ïúfµÈ×ÈàÎÏ÷ÔÝ¥¸X¸¹£Ê­ž®)ò¡™žæy¢$×ËŠŽ,-¦û@MA®'X¾Ä–t‰?ßòcÉ”¤Y–E[/âÂfm},G©gÓ¬¨HÄLzsáâZ‹à@žýPζԮMÅtcß1ÿ1"j@ÐÇû«‡Ð4»{3L{¨o„7Œ^[¥‡¸ %Ä &Àž"{å Š"6+º ™†+d'Ö&t §Ç»ìª‹À÷l£–÷—Ê·![e ÏZµÎºµJ´€ù­Ftæht‚ŽòMìú^tŠ?-´p84¬½ŹÁŒÛeú~…íü •¦Zéq |;ýˆ7ñá™ûzY{¤šk—OÊb€Y3#4øÆé´7µ¤) •ñŸon‡bír«Ü.«4´q]â£fSxQNšÚøþfëjgû,óWÚeÉÈD†ÒWüˆ>\€Ø ¡« ^`ÒÜÅŒé4¯~I‚±mOC?û¿`‘·[—¥±>ÈžRŠ^0:xøÁÚàƒLÊJta —ˆ‹lZZ’.‹|(Ò©Sù{€¿‹ÔXjl™d±쯵Ò¡‘–xçô4Àñ~(ú`-ì”x®õsn…šûà4Ç¿å°VÖ3ìbjkó: ÁŒMn†‰j†1Û›JûS¬ž[RXñÄN~$‡˜y÷ßM3³h=“ø¶–7*¡ö ê—¾ì 3ÀZÈrͮᩀ$/!‘-—œ3Vœ\ ò¤2/ÞÒñj„OH’rØ7˜#س5‚Í ˆ6Ò¹¨·ašÑIÈÅôJÎ ‹ë$ú0ˆ·²Ï|øÖûOî>ææ%<1þf<÷÷ÓÒœºÅÞç\ NaI6ãydhMU9*cLîEG®ÝÌFŒ…Š IWò°Knc°–ñ0ê[›‘ 1“Å:ÀØ(“j%,R"}ÜM$~yC Á,uw;«oÝÎ’—mg´É¸lü¤0°žà/zøÁyøÁcžÛöÂ6õœð8à ³[_0}1·ýp”ÿ‡ë)Â0ˆÝ¡J€ñÏ¿ãQ& w|fߊq±î4šìÞåމ͟pàþ9`‰xÞ‹ŸÿE‰8—plÞûøôi½zÚ,–sq÷åÓçYaöé.º¿›EËèá>zxŠßÛD‹åç•g±ÜÌ¿Ì×Â/„~x,'‹Ý­ž>ÝÏÅ÷õüvñ¸X-4\À:0.uÑ)õ(>Ïn7«õ£˜eë|š-ïÄÃl³^ü!>ýóûÅÃb9ÛÀ«²×ÈâQ<=>Íîïˆ[øw~‡åáÕí*Ÿž6b±çÐà\¾V•Ð×*ý¾Ø|g¿-–_`Œb³x˜‹Åg!Ö·+;X®6b9ŸßÍïLïä|¹YÿÐà# ¢€†/–ESR} ‹Íl±|›¯s5Þ…þ# göe^ôòvuÿô°|Ì6±úlWž­çTð€c1±mg[Á’w‹Ù—Õrvÿ¸µÍõê÷÷û1Ô’úòU${ðóá ž¨NËÙó¹„ïá0ùSt¿ú]|^­ÅÝrÿX¶q (´©0<‚ûùì§ñæpI„$G2[¯g?rAÁ¶ž7H%eÄ8Vòò áÀ±”·Â±ZßÁB‘}¯Ö‹/@¼÷NkÐÍöÖ–OŸ¸)3;Œ(ž ˜õ"0°Š(ßÃp —òý¦ °»?½¢óÙ§Õoóuþduî—yªóÏŸ·  Zv¬¬gÖÚz¾yZ/C‹ ÷Ó÷ï& w¶üòt?[笤|Êxºß,¾ß/æÀ~ÿº¸ý*~Ÿ`O@ò›•X}ÂE ¬$0¬ÎŒlñwbPŠÝü¾^l6s —0÷û=Àõï_¡Ñõ™»XÝ=ÝnÝ0œ‡§ 7‡xZƒIÒ›7ìÛù#ÕOÔ®‡}[P±(âü¿Íqœàâ7à‰‹åvç6 ;Õd¶=4MG]?ÀŠømvÿ4 õX|D O…oÑ·¢(ÏÿsšE!ÂaT’)lóõzè…>ÈÀ„Dä*TÑl{z{¸[Í M8Û ½Ï6¸«<ÞÆqdÿÛânŽ[Íßç뀚í95’ÙQ–¼AT3 íûÅ ö‹í0Hfö¸ài\l~´ÛDnÏ…`$Î$Y›jÄt»º¢B† ´÷e={¦ü™±Ó øq¾R¢Z‹å÷§MÙëG}`õ‹õôûâ¶Vì«И fäV4Œæ™Šè‹4Ü:Xæn…rä¯$¼‰e¢ÅeLJÙÂ᥇§p‡X2QÐ%”ÜÈ{™vÅÐè"É+ŸoX$×_q,[Ê¡<õ-úeÆYa_²eYŒFáb±|  üt^Ó"b}¤}^îëzc·vöœ­h{vÇ‹NÒØb +mtÔâb©ÄÅ`?{ëw~?gàË|9_Ãê»wOk¤RlÏp2ÉoËüPdµÞb6/ê—å7Ó= ÓM¶A¯p…óÉHïçŸ7†{ÚP°°SFJ•3l»ÿW» Y×zþvƒå­-SÞÃÒšÝ~+ó,ü»®ú;BAåð ®45¨·÷sX«ûù: ‚Šo~à€—óßÅÃüÊÀ³5¬òYz¼ÜÏ>™ ;äMãóÓòË=Þr?{þøþ#º{v-îf°Fä[˜»Í¸0®š„®‡ü½$¿&ö†M2†2ÒþÆÓ0²“hQ‰~~}Š~ý{ô+|#Ø ¾ÇÑ}tÿÁÑò!Æe}Ÿ¨VaGB‹–Y6l© ï3p·P…–¯e­_1:‰ÚQÎÖ_c³èŠ–Š <¶/IÊùµR_V(4T+z¸Ä|þµaÐŒÑÔ ™°îÿn^Xlª<Ü;ê&2X÷·Ã6¥¦©W5ëÍægÕýÉ"8¿>9Hú2{z|\àkt/V–¾ÏÖ„9’`Yj”Ád@K3ø”P+ÌÄ6j0}Õ7ɘ,ÔÀ<“@,Ý,0š»åü7qff&×ß]uŸ&éï Þ£(ª ±­¸X@ Êq¨[ã9‰w™’ZfJêþk\Ÿa›¸wjÉjþ‡=¦ûE| x/Kß,ËÖâõR¸Ø#„å¤&Žåz°¦C°ÄWø†`â:ù/2è• < @üȼˆ‘,f÷kа~8LUj‹¤ðÛbÛ^q¥â (È'n¿Bs¤u/ç P>ÎH¯v½çÖTK kf6¸ÊNÍS ¿|ȼ|à—i\Ï™zü"£&Øàa÷¥‡yí%@Aœf'ÚðìÀ,ÑüxýÀF•]nõDöjrÉ2Q ÔŒ639ÃÅhiAñ@äã­©˜ÁJSH=rÉýe&d¹Ð—Cð÷DAién2ÏÍýê:]ì™ÕSÛ¬dÖÖ½”wy~#ú)OfÓ8T<†gÏîhÙáøë×¢“ÌÕ´t”y¢>’ÄcâÇ•œBr7úö zeÚ?«•L 4»KéÒâ±LvKwÅÉžT9©Aó9hÂo™õŽ[µmŠ„ßet7‹î`_ÞþÝýÀ¿? ÑÃÐ73PûÑä† ŠÔ/¿ß?™_JÜ!™ôi¹^‘ï~µúþHú4¹–òâüŸ`[B}}©•Ê_AžR^~A P¤$¬HT⤩r¾Pr÷6ï~п³¬„‚CÂñD M-~ 8ËÄìC‹Ï…%Ú1*Eñ8[w3gž¼÷lßÇeÈÊØý*2y%½]ÝÍ OK½…xê?³¹ ¡c±ûËq¾øaÿ Ϩ©X¡´Ü‹{øÔ–·¨ÜYî‡Sî‡UÎÈ8ˆ7 `|ñ \~ÙZÚƒÉXüa­zê~½bçÖsìnñƒŸÿr‘·„²¦$ÅO+`¸!Šb)ÓT¸ŸÏ–%Ї‘u$mó[ÝÕë〠x̳-«YâOUaàÁÅ€B€5þbXŠÃ.–ÌÉkÂP‰$D=¸H¯s—D®Qm—níØ–*ÅßuIú™)X¥·t’-]µJWÝÒUuëDx>ùÇ3¶g“›¹ÍÚ KÃW6+Mp¦ùÜά앜ŒŠ.>/Øny»Z£—­;ÀÛXžXο€tñÛÜt‰Ãƒ$>8ªlã†8XsêÅçƒìÎÿ ÛÎÑ 6vâT;2§<¦CüIïy^óBž˜Õr“úÏq“?ä²Þ•‹Ô_ÎEêÛº³ßhîâš+8’Lª[ š)Ps ÔþŒÃ['Ê®¢µe–u ø( ¬ ê£GZÂÄWvNBÅ2» €2âØÎÿÁÌE%4 ¹Ã6ìÁb „+ÄÈ"½Xøâ*Ûl…˜Ç?[a(ï`v Ì?Švs¾¤b¸Pbs!èÍnÙ'6¬VI…—…µ¾r`¨‡Àx&ÆœÊëØdA6)w˜ÙQV+/f1‡£ýÅúú†Â1Ÿ¢_WŸž ¢Ø+b±çb( Ô'(*gÈB<Þ ` ¿Í™„Ã)7UŸäß äµÎDÀèrÕVSÖÍv ËYµ¹â•¾Ç UX®–d µ+¨E¢êå9ô!¨……'ö_Áƒï«Ç¹³^²¬W! ëÐŽ+‘ kÔÔ&¸qu;‹ŽüÔ̤§šœ¹«ÛÛ§5š"´;W®o4ól«¥ãŠE?üüöërqK‘Wì“—ÎòGÛIm ˆ½í Œ.¸ˆÛyÿ°ÅÈ è\›­¿w[ «iÅ‚ ø™ÿÙœw+þ ›¯õkb[‘ïÜü}û„ÌYtÿ‰ý˜ìÄäRÊëH~L%^†=kÈ÷ÊË9Оå®òø"²¾Hs”·'ë,uI<Ç5 €äO^­ÎU[„€Ý[âþ‰v± rý퓊IÑ0|£™f—ð·OøñOÀÍdúÍuN㻩ï%(d=üDîU÷!y²\´…P´+1rÿ‰R àÆãçiß•›mäo´ÛÉU{*zd{‡ÎAMyŠp]#6¸ð&¬@KbcO[ãyŠáÑÝ=º .Ê£í‹òÈZ”‡Ñ9þvÉ`l’Û²R-jD#­…ÐzÑ †Öwh57+ÛÖÿ3ë»™Y߇.y¹?ÉY÷0*gö m%"|.ó=g°3=(UocŽn~_I!ññŸÃqç÷ûÎpø&‚aCÞ³LÌÿ—ºÐ$²øï¾´nï±CímœhrŠìùý üj?i  …±²›QÜž¼Â,žß·üE¶ð=Ë­Æ•÷t ʾç8Ó” |Ïvš…«Öt¡€Eœv¤üYåoÎe»Ö&º$j‚éj.£ngu£îÕE„i™»Îðå§B_•ZV'—M':Y¯N;‘0êt·ðhªïÊ$È&Á«  š»h}åaÖ¯^ÊÙí¿Éeo„ÙBí,áÚ4 S ¯ yþ—Š[H“×Û¶&“Q¯éîp2fuñÙèT6…¹¡¼e}¶­ËM'EÎS¾kÓ@CL#LíšÆ®.¸¹*5Wݹ¹^zÆ9‡J†Z7 ôÌ֨њltO^£‘ÔÓ<íñ¿;öì£hz=R(â†sào}fvM_Œ;i{ZÀ›/o¢~”Í™ù’EýŠå”¿Â m"ZÖm©xû(L÷{Eu5\¯ ³9™Žðòw^ZS1}£DÖ{/LÍÜÿéK=½¤É¯Êö‘¼ r¶dîiva}Ôø±›R”O5Ÿ'äZêûUøÃiÔ„J(Ûݲ™8¹û²Ù`kE½†ñ\0]CþîO_He”NÇ­iR¸¼¼Œ¬ë `Ut§­î’­q/jC¹n4¥?Ü ß  ¢ëÑøC·Ã·ópî,Àïb¬Á)_…Àרm8W!`²¬þàÄ¿ÃÀ,ïî‘ÑðdOV0åô%½ä[^Î$Á<¿`Èp,ù¸?:£ÔôŒ‰×-%@2f'âÎrî¤+OìÔæöÐUšs?•9á_¼4§ùëSš¿>‘9ÎgçìdÒÿé朽|wÊzá€é hi·{Õ4Òݘ'ê€Ó¤ø’ f–ñ9NëÏþsv@â'N¾­I yf9·%'‚4¯ýÜÁ¡ÉV}•’¡ÙÏf"eHÞÞÚKs$û­¥;ÃÊ’¼½5/O2¦ß£Ø†l"cbR˜©#“zw“˜Ò8kÛ—w»ìÓ¯ ,ÇêË13ŒÛæ[ògKª¹ $A}'¨ô1[Ýߢ´·‡1RÐf>X&‘{øµÎ‚™¡êú%™z×óǪڛèGô8ûmžD?¾¯óhñ}¶ŽÖøÏb¾^[—ý NËgÝr’¡5•¯qÒ÷ò5rzòH^À»ï?;í".nDýÝš¿Q&‹ÛÁ&wiÊš2”Ç‘'º½›9>¨þJ´©Sp«W5iE+¡¶$¾…Zªépö“L¢îƒ‚ÉÔ­`àÍÅþ²/,i@tÐr¡s,”âšX;%&¢x\@šˆá[i¶þŠÁ7ÿû¿ÿûŽ+yÖ;Aq,ÓÎ{Cá=J•§ã«n9|Û¹G–À.¤¹\Ïáÿû±V˜ÒS¼ªïœŬ˷¯À&;M[}¾ŠzTþP¶×Š`Úqÿ餭£Ž® Ôë.æKÂˈ1½¹Àã|v9„qÿÕË¡þòåð¦×åv'SÒéžøñ%–$²`2?ô´bÖÓÉ4 ’åm>Va••ßÂcO†tƒª–lKbÑ]Þ-×yXf&h !xûKtÁ}ŠòÆø ¡(GátÉ•ò^Çðv:z«W70ƶ²!ì¡ÐÙ#éOÞ%ô‡Û-1I*+6uÑâCI_,R;ZØ3¢¬‹!)Íð¢S`ݲóRöàÈ8ÊИCp ÑxTõ…L<äÄÕw»üeÆ"2ŸzQUÔFtëd<>œö[gZ3õuR÷’¾i4…æ¢)€këʾ¶M–w¾ÜôF}··›!=BE›`ì ëtǾ"Ì&.üÇnÀ¹=•``Ý‹hxÚJûæ:&º›‰UºÐ²}Í<þ™L/¼[ Y÷~í5øyƒùU†ônfŠñÒI॰ûŒèQ÷B1LRïä~˜íÙ$Nq«––º‹ñ€?nÉ…X\Öƒ”wçQÕÀ:3pæ:< '°à‚HÜñô{Zó¼aÃ6@©°û03ûUiRÀ«ƒ€ŠØL§{ä‰gÝŒŸ{™·¼[ý¤ÕþpÝwÌU€Ð)&áF²…cì¨loKôÛ—éàj ÍÁ­@fØ40év3wl–ýêd7Û‡ÖåøbÀs@G,œºiIN½Ð€™®ý!—m€W2_æ»­vÉaÚúÐ*`z¦|9IÿÖ•‰«[SÌa/kãûa÷—)Ê ¤‡}µúÓ¯fd:Žl<ê[9¡;Wc˜)¿¬!)¯Œíµa¦†nJ÷ òE”»tÑ`÷¬EßO®¦~+étBWŠÁHãîhk`Úƒé8ëÁ”8Ý)DK”€À7šV$5Å­Ê@Ù•«D.)…2ÝFëlƒðGò®"Uï´œàm7t‹!eï Ñ»5¼É`X+Ž‘qcæLœ7ÑzhOŬ»¾™•žlL F³JaÍÅ r1 n¤M¾ºòBÝî9úاMÆQ='&1úi:žHŽ»ö3+~pª«K î0¸ªpV0%zwJÉ“ã(I¢„îäLjˆé)’íÐÆ$èG`:]¾z8Æ ÛB`†ó©טtôªW§ž^õ¥K1—Æ«'A,„ R¤|ÕïÐDàâh÷ÒîÇð ”ô!ùö&"¸B•’p_(»ðúW¤X mͬ³€³³ö5µAe¶.«È“ÇcÎÖj ÑÎs{SçýÆws¥¤Å¨àÉT‹7¢QÓRšÐZµ涀´[owžžtÏÒ!±{ë^O·2Í´f`,÷÷$çk@©q;]L å"Úl”E”Ö2-LÍ‹­Éµv·ú}:¥Ô¶þžFƒ%ž’K¬@¨rûæÚ´æ2,—•"æ|1*F*pØåÞ ¡UÕáé’`©5ÍâzÄpýAvI§‘ÂÞÀ²µ§[«Ÿð}eÝqÃl’0Ì ðZ iS&P®{i›W¹Rü:lx÷q&£€‹1¡ ·ÀlȲ/¨ÜÎL,«âr¼q9"LT#¡“‹¬“†ù›»Ã3ø¦1sq­VÛԩ̨-/;Ö´‰ófKë@‡7€À«0¢hN«z³¢„Ëé …:Ѥ Ó—°Á rX Pð¢„ËÊ ÷À°,æ\m}CbËÐÙÞ ¡/ßÅìÎÀ!ÎÍBâoàÔ]ØÅtÜâ¡GeJŸ;¥§(mØ× [Ÿ<˜DáÝr Š“Ìæ(l˜€cék-Záñ9Î'ªþËû ó;Æ«6Xa¾F•î6Û¼„ÃBˆ5²OÓŒþOëkèâZÞ,x„MajÛ0BB¶{+N`+¢°¯\f»ñïÞæ“.<Íßô‡/VVrxöRolüùV˜-]OGÃÒ¸uÑ›Œ¶"ÏúÐq$Í;ÝKjÞe |i´š‰5ÝkXÉBN…1#á¦mî-¿–ߊþàVqÒÔw‘€ˆÏ)©±}5F)‹VÒ?&*±°F~ªü¾¯rñö@¡žü­D±Næaßt»×\»®`­¼+Ÿ° Ë‚w÷5Ûàa’uë´§XyˆÓ¿àök¼q&¥Áéß$JaëÉK±@<š.úð?4«Ø– ø ªdÞ6ÜmavІ"¯ï^_zÎy¼÷~Ò‹FÇi§åºêj¹ †B^º€¹ ÌS2¥/yAo;º½ÙèÒ¾¸ioxò'Q¯Ýƒ§gø#—¡OÙoÆl[2¾sËôtëð—¹Ñùñz÷€ ÞŸw4Eé¤5¸ˆÒk\øÑ9ipÑ9𨫋ˆ·Ö¨ âh({”?ÿÝË6¼†¡Äe<…Æ— þ‘æ-Æ+¼ˆiù-8W”GÃKm7£mA™Ï¦µ‰(YÖˆp ýP¤.Q)`Å/âsÁ„J?"mŠIµ"R¶(T(,ê*)èå`$”.ʵ›}£é20ÂG5ÂÏǸ¢)¶F;xÌZ¬ª²¼Ç ”D,wD,Èõ—âX®.l«*cŽõ¸­PøµuÆ#t18‰ ‘þHr^«¯ˆÄ€5šÈ% ©Éƒêž¼9(³†]·Å~ø†1W*1"Ì]¬ÒÙ7 ‹ï¤ ¨K4÷ìF0œÓû73‹J{kOèî³u“t¢ì±²j ¨Ì•\>1νÊš¸X)Dé“ÊDD" Ên¬º(#–¶²¶ÇÝ–ZtÙZ_Û…TsÚS踸ܩ)ÐúJ†ç(f#FÁB›—ÐX ‡Ñ‹ÈpDòÝQ7Æ×xeln³C‘éð ý³m4&¢@’dÈ4?YBGl™ÒÊdA òhRÖðZ©Fü浘PÜ«¥ iDInz{Ö}¶qÀ·‰[%†8ªŸ¸\ÑÕsЧ×*{øZÑ,¬ÞcuÞ€Öòq¥œ˜«ÂeœÆ´œ@Ïê}lÞ/­(f®èUÖû²1.ø]ÕË fÇZ^„mœBøØ·•S:ÖeÚ®™Ùï±€bnæ?•ÚœéP*“&Š€ øžÛ 3A÷25y¬'qbÿºõ˜ãÂbËc-Å8J‹Ç±]ܼKðÝG AŒQ=ŽšJÚqh–ÕtÝÃŒ—+ôdwíw|Y©þIZ¿i§µð†m7çÍf[þvp+µWRËtžñ^‘qnÒþe3dØKŽw}…¢Ð63œøÎ꺤€^wЀ]²,¸üz0$Fq·1Œ¸ý›¶rçAâ>P1êwO®ÆÞ[ñ'ÃZIycû-ªwÊÒ?‘ ] —ÄDt#<²áieU€= 1(c9šH¦e<|>iÝJQ+>U\YYFÕ„I­‘÷»áe™[°IHÇZHu*¬;ž"Á2@ô™2e>e¡Œv“Ùˆ ª¡6ÖäÉǶO°Ýd3„†‰ù !c®,IÖivöþ~Œ.ÆÝÆpz5&g’¼Ü·ážÜ°Zh"Þ°ÅêͶ+µÒqk&þP¢@Ë2-È¶Ž¯Yé–}æòÒiBˆ³Û{¨yHš“oè;F Yq¡,/c;ˆpÃßЬcñ$6d‹×óÃ&dëH¾²]4Æ’d¼£=Õ'¾ß&€êRmÍcÏ™%ri†m˜Öl.Šß@ƒŽø2ÆChoæc«“Ëvwz{F§SÆ#ï´ÂO@ñüº (2»:Üô íþRÊØ}…¥¹ZÏ8ŽBà¥{Öà0±oHrüRÏ¢¶$gö­IÌíNXÚC ºuè¬M½“Y—©Œ¼ðN²eϱa ‡s\Œ#Ièìš}jÍ´áŸ_ãntPÍ;œ&ci0ªf̧ÍlV“#£nP///A¼Q«a8š²]á¥ãIçì/BQ€ôQŒ—§ðeº|C´hú³MÄF0éŽÿ§Â‚¼k @?ÐU¿5N§7J•ÌkòHžc‹Ž@8–Y¸ Jjá¿Îµ¢,vÕê¹æ/ùL^î‡Rf5 efŽ=[+М±æED×ú±ô޼zчø,2\H\ãóò|B‹¾˜ ò³ÁLZ:HÚ_ÆåAyR¦@ÜÈ騗lç&âÀW\26…ŒML+tV· ¤ã²:Y8ðx º!Ûí«ôÐ0%È–>òp4rËî9 F™ê“b’ˆ4d#ýÑ|£Ž¯Ý¨†4‰g6Fc ÆþÒã7Ìf–I .³Ã=˜¬ /{0#'o” ‹1¢Ï“=^˜<Ê«ànÈ•âüìQ^v2)+¥†ØU‘š°ÿ©ñSùKñ#Ñãl–Ê[Â÷‘Ù 42æ– E­à¡=dÎSï›<µ|¢e´e¤ Ó}{;uŽ.J¶dŽP| ×nMÀÖ!˜YC5áäA¦ÁL³Ci }>ëãèÅÒüaÚ (´éø¦,F(Y_§Òc±£q÷¢Û#¹ÀÓ£lž1M°®­,Z”£L%ƒGWXÏÖŒ&“”Nݦ§Ìá, FÃ’ÍÅñôX‘Ç¿5ÃŽ£{Y.e¬wHи§“ŽÏ g ß‘R. Ÿ€bvÆ3Pg\.d —Ë>_öÇ<8ÕºŸA?V…lÙ‘Yö(Nµ® o6^åg…l!¥Ûic¤B`ÿ|ž-0¹÷l#7óï"Ÿæt½ ¦Î߬¬Aì*±xèÓ²¶ñ"ðïl° 9µœ¸GJÈXP⎲‰½£ ks\Ë;U -*í]^úP]¼£6LÓm-Ût´EשGCâ2qNï¾é朮ó’kïŽC9r$Pç `¨Šæ2>ýÁ?ßQMüXi(•ÔÒÀ¥Nß²\B¾éБ uüï vÿ ìp¢^œÁ®‘üd »F"Ééõ)ìÕüv±•îú HN;h4.Þ‚ä çÁ€’ÑÈŸ20ú‡£?" üøØOTM »ð3[Å!¯˜NYE‹¥_,©Û/tò*Ê]…õ È2=Šÿ¸gݰ›Äœv½œì~¦1KÃF%) óÀ ¡oPº*‚Fß½ƒc ùÞäé2'-nàm¢ø''ñ¦ü‘üÐo<òFNˆ’I”QŽë‹6“$Î÷]ŠŒó2Éñíà½L*>7Ç®ƒAw?0ç í4„½]⾉5Ìäs×Lµ·W –±)樄Œ}êvÏÚ¢ìì’ÐdS²öØaí"Ì®¡}d÷о‰k73\;°óagÈQK ”ÅÄÚ„ßQSY5Q¢ÕJ‚j6#þ3|¾š·‘_#ÌG2{“œ2lÿÇ˺0ɪwñ Åu€aÃÿ-%J†¿Q"Õ8/‘ªÞ¿ŸO£¿*C0à=ù·Võ/¡UáD½T«ª&?©Uaøù­ªjiUo¥TU·(U²çŒNT ˆ~N_Üu<=H~ü{7JÖ.U „/Px¬t±£a×Éc²Øn™¢_åymç@7sU›\o5þ®Çé´+ ”6ä8™½„ó݃ÊÊ'‰*U’]w…|#œgpW;€ü‚Uo ²ò%>uPe¤*ŠJAã¿¥·7¢›¬}|ºŽ çeÙŸ—nipÕŸ¦xT†jëlðuJq¶:&XY¾ñÔå¿Ä#réèjb§'ƒg|vK3攎œU MÁem1£s˜ «oåTÓǶäOÔ ¥Mªsøên©·ÅÛ’'ë:fÛ^g=»ýñ"Ã_Åaúî­ýn]õWë?k¬ÿ¼A°Þxû­«¾Í({&UÏ :ºuüglæËÞ#%kó_cíËÙÚLÓò‹ªq_ŠCfÁÊ«÷:¥yÉŸ^Šœ‹K´ýA§ÊG»’Ý8¼,ý °OÇ[j” èæëë2Ï<”çž' „:µÒ£ O\a²øÄóè‡,ú)GÑ"¤ü˜Ê—´aCväšÊúbûh<4Š%YGÀi_C°KU-fÔ|ëg¢ÁWîX›°'5¥ÃÉ•Îú†Q*°GÞhè/Ô ¸sPà<{]$+š“"à §—W¹Ñ)5Tµ¾©†ôlªv†XùÔ®¼—›¦ªMîʾèC«Ðh¡À$o5*[s³¶Ëtq§»à^¸9쉡-J¨ùE˜ïpŒÁeÌP´+À œ(³9a2±c¤cë<0)ÆpÒ{Çx0F¶»gQv‰&¸hï„ ]^ڦᗓÇÞÚÇÁóðB‰?îº»Ê N~»š.Òöà yvÇ* Œºmƒµ±.Ô7)Sy¶9¢u¢ÎÌãù;X_”b™Ž\)‘mu”÷Ç›âÀ6wÔ‘û8‰ÌûAu³1`æɘTJæ§adL«ÒHô8¨Mg %_wKêìA¤…ØL§2›"¨ L¡©Lá- CâŠi…„Uª€Ñ' [«£°ÓÑ&”nêúg­¡½ae6>.%o}V­UlƈM'ƒy¶Ÿ#ÚÏ-Ó@˜wòzæ½ã™`û| ûêxÞbÖ ¨Ûb2'{­CÆö ㈣ÇÍ”Ó ÒIc™RM½öŽ£’Š7Z7~Žu”ãç³Ý|æ‡iYèUn#(œ`—¡&bã×H$ÓÁ;ZWÎü„䨳• ‰$®È“À¶óiñFž¡m!6uÏ™sBÝIuʼn­´Ú•Ùh"øaRÙiéÁç¯M–²ÓÆ "¯¯ÅùÕ€BÑ8­šš4pco7«Ñó'˜¬:•*–Ãíð,¦Ô^9£ŽòÆ(R±âs¤1àMù–]#×¶þ"ƒ ¼‡ÛC „d@­¼äaÕ¬ NåðŸý‚2Û[þ_£¨†UC¬UÍaî}Û™caØ£ï”Ë3píYV Ë61ø4¿»ƒgóõzµóÇÍâa¶±âܶZ¾|×c`?4·úÚáVÉ >>O¼p«j(nC}ͯŒ·J¼€«„"®ªoO5àí¹[ÁãL ¸°"ù%¬a‚ÿÞ(ÂËÙ¼hªò³r&ƉHHfÐ?Œ_1«s#£'MÈ©¾+sþã-,rË‹8h]z[¿ì׊2ߤðV¢ÓdÒè„[¬¥}êˆ"yõ5vxÖ\Z ù …væÖ´»·´yäÓ¦Z+F)U¨ä¿%ã²#¢Ž xõU -¥^qϲð{º^ØE†?8íîgðµÐÒÕO%„³L'9y…I ÈÝðlçît«Ù€^?å Nøü ñåÆí.’ðQ؉#ø'‘fìj¤³±šº=yÏÉ ¨~9.àQ¹òJЀúÎkùc?~g™N&xæc·ÃUXÇûqˆL(Y_³RX*ÏMË$¦nšäÒ!ªSð“ÂÞ”7ÒË“\˜ ²×V;E^(d yô¼ÀRo~:F E¥Š‹¯ÜÙO, €é §îi/r±èKrU™C§Luãœø°-Vuñ¬a>¥¢“1¬‹ÝlëVÏØÖ †ÌëÛ|ÂÐBõÌ·° Ù·7èChñ-þh#ôGÎ…UËÄï©ÏVC¼`º¨‘˜g›â¥ùÛÙr øöxjDäá `«a^Ôh˜Øï“m<¶5žZÙ¨Ü=Rð6‰±F¨틚 /íµl÷f•ŒmWÁµ #vÕÞêËÑØNî@DÀJ¯šYêÕð/«a[ù¾Ï˜ ØènhÕ…ÊŽ°š}6®É´{ر§ù‡D zòŒ^d|üB:?޽g€åPÎja¹ÿ%~s\$"àUÑ3áOD¼e¡é)Øæ'!|&ÒTÞe\&Å=äÚžuœJÆ]@Ú Ø›’]=!,‰ ßIc°Þ¬…"g·!g 65TÉ©UнzܳÈAª¶ ÍVòŽŸó1Ù8Vô<МĚ¾cMßMgrÄ6/„†¢ò¼ßÊ¥"A‘°(`*»Ãð@䬮xhð$PŽû@±š¾ØˆÅ/Û6 aë„éaÖɼ§â%gLõ»lÞBóM½y輆ztÕ1©+|ë1–A,¬N\^­ø|*û\ÂŽÝáÏÐÂEWC‚°AîT…ÕÐDkO†¥ØèSåÕЂÿ:#<ä6¾½áÄŸ³íYEä¸ªì¥ KöÛwº}V·tj+€ \ìdÈŒ“®›ß§…q¸ U&º}|E!uÅãØ%ô¶]²c}|/šÈ¨“"³0ÜÄ›v®Mñ¬±\Èp1΂ԘÈ,9ò-°ZÊœQŽ¡ê,,WtéÝH­³È°mÐ 4OY„ðôí )ÂÇŠäQz{U•U¹±ÊÞÎæ¼qU™ÃÑ6>¼ŒD_)‰VºO“YOGãÙ㘠XÒÕ…u³ÕœãÍ2kúŸrÐx»|¬y)›v䎥uDú“÷ã\2%ùJaû°†9€Å¥ x™’Z»í¦ã–@u\†¾‰^Š69‰ªŒ\¤: ?RTSÆ%ÛІ¦Zµb [ŸPôí¸×…CÝö@mË3 ÒKí"ßÙ"AÈu¹ð'äx±`ÙÍ/À[†­…3{…žK:¬ÀÊÉ;,rR‹€Rd<Œ"ƒXÐzñ³Û, […YmE^xM­æzcÞÈz«»œÂÕJ§ÀQ2Ó­‡²*§"TüiÏ\‹¤/1rdzQ­1ŧª{på¨ã‹Q_'¦Ptì.ª5‚ï;Â=¶uÑ·»ó©¨÷ÐÎ'#Bì­Í4eK0uÝáÁÁ« ¼w"¹ø—ƧRàéoM€³ Z2êÆ$õ˜ŽF¢ßÂä*Î-<îqhIÇ2ÓhÛùžBìs¬I‹"óŽÍÑG*„à Tú&•[;Ǩúìi§Í×¹åü}½ØÌ {Q|Ô¬Ó±ã&åþ`F! ÑAôžn® |RÃòHz»…Ç¿ùÚÖ´ßïžá…—òŠGn|×è{“hÖtùõX|=H/`®IŒåsq%ìÞò´C¡Å ¤Ì£X›Àµ›ìú#v¼÷ŒÙ—l©én±^XŽ'/MÈV!õii L°¸×Ãsb왌0#X“Þý‚WÓìÐäAŽ=¨a‰¨ç”á£ÁÄ©a¿”÷Æöèü•¾©¸cìÜ #A…8˜×¹BFý%ÈÈ^lòëãf¶Þx«_V›•Ðzø|y·øüîÖ°tâËEþŒ^…éð.¯!Ÿ:tÔŸ„ÕáÎHô6w»úoë±|¹ì+Qùñ{åÙ© öõ'\t€»oÊv‹<²@P8ûÜ‚9ÕR‹Û÷娥›”5Íj2£H6zlŠrÇtqNúŠ4‘£¾¡\_>ßJ6!HBz†Ê]¿è{ºÄ<ÖL;2´ìYÒf˜·}dƒølPGx!i/çÛ7#úfÄfxX-Br„ ÈS¨@Þmä.ÇÜev^ñ³æãq-á3SÿjV ÉÍ")-]œšœ}QÓÜÁD!ì5÷¬¿¥Pl_@ô9©g¾ü?1‹©Ñ8ö5Gz}KwÔížšÖíî‘Ý·ß{³—àŠÃØö$¶CÂV-y’™þžR*HP-ië)jÖh=x_Ž‚ÖèšÅrd͵{²çT+t·=Ö1åKít¾K¶¹×‰Ä°”sá–ð“mŸÙ[‚R+äBÊù¹CÙRn ycf;vˆù ZÖ†sØÝÛ&FBÊý[îQ˜ücÅÒæ«î‘%"í=0èû¶Èƒ€Ùëáô¤gËÖV@Ríûo^2›žœ ¯‹Fϧò‚U ŸcßÚqŽmÑöü}ù±mÏÑ8÷%Î#¹–_ëµ|tú2ÒÛHªÛúr‰ñø¸¶¾½Ýë[àú{³mOxDÉX_»µÐ>¢ú¶º‘{{Á¿T=.=s¸ß°¢¶â‚ zjé²NñéS¹PƒßÍNwýÕss²ÜüÐ¦Žž–uµ›µ%+æšÏOŸðiéE«G¥ãÀÒ¥¶âïê­sŒUØw ^–w{õþf4öf‚›éÁα®Þ¾žÈ÷¼±ÆñšÿK™½’ÎÐ0=ùÔŸ…–ªtµ¯9ÆþÃéàV¿÷_h !4ØÏ$'N9¢ÊÛSpÖìúô£z/Ÿžèó^½$hJâÊoßàé›.¶ØJÁ;gæäP\¿ÇHÐõ/Nûcå®Jð¶D¤v œâvq>þúøCñŽþ; ÛÓ'­®~ Ey sË E–/®ð<(fñ¦2ÊAE:XŒLbçÜXÅ/RÕ#”Ò`FÿÁ¹÷ÚnŽqâŸM $ ®7iž™¿éŽ·…oµð©ÏÀƒbYùäòv|3“/T»ÂÓ y¸~½°GWãú0¡5µR|xVxñ˜y©Çoø¾u ® ÛãÁvަ8´«IŠÄcöœ¹y]Fc!J5NßFoÉ¼Šš’_ba-+èùîÌpø®Ü¹6¡g´Ô†¬»M/Éc¤ñï«çÐzÂ]L:Á Χƒ‹Ñ»†]àÛ7šjý©…/¢ÓÁ5ÞÓl¾Fq¤Ï"M6y´ Eã)L³(Y¡£Û„–Ø>ïWÑSOƒÍÂÕ*̲0ô̳QG÷IºŠ1 ÓÏa>{ârð«˜æ‹Ž'!Œ’M¬r1Yey”or0H€&.ƒF b1 î<¬â&š‡‘ÉŸ%ˆ«yžÜ…©8êz¢{zêól«ùy)‚Ü,ÃUž% Âz3áþ¡?D Ý—Á\oÒu’…øçø9SP,Âc®aDꘇ$YþušÒŠãɵùr'F(´H¾BêÖ‘S~±…”Ô4ñ=²úš%¹ ÆÇŠÙo7)A>sºÄÛ([¬áJ¹PzèçÜz*ìï7èT€ _ñ<‰—Jz£Õ<å‘‚u™Kþ€þ!ÙþÐôWä\¼­ï‹ Mž€¬°nCPà.:bÐîé‰ßƒø!!ºÒð)EÁò’#Õ’{C0D´>Úë$UcñÔÏr™uÔZŒ.@…ô=qÚ;mŸöÕ’ƒÁó·"bc+n;bȈõšâ‚¼]˜FÐ B¡ˆ*\5Š¢ˆ"8â C£ ãOø'Çmÿä¤óÇxÈ/÷R¥.Ýî­NYÛM·¸¨ðóÐàŽ¾õØÿßÙG<›Á³*Çm›£Y1©iUî_ç }QFNÔü´ÊYþpôd°Ãv%ä¼ôœçŽNÖy´Œþiáü‘7C\H×j-qXðL™lÄ1†ÐÀ¢ˆ(ò !|=½¤€¦‹|Á»ö1'8ŽÖÀ=ú6RÌSE¿½›LÑ Æ²zämßöí9ÿ_yc…Õºì„ã€~kà<ÃQ™# \ÝÔ³¶,òö ð»|›lùV+=üNs±©s Þè\‘þ®Šô[(oÀè˜r å¼S ý°Lz‹C¶Á«ø00\ðwqaPŃ!ñ`¸ÃJ û¿‡Â¹43;(済ær„ÑÃãý¸Ù¹»žÄÖe&”]C|Hau¢]wÖJ«•{ò†ÈQÞÉa£²Ä^!a”‚e ‹2 Ws6_ X ²¥^wü>ê…9þ¢õ«…ÈÂMA¡¸´ÉðÊ­'¼•@4¦Ã^¥Ã2Ö}?´{Á£jy(É<éTlE’kï¢l*&©1‰ÙüõÈB xöVþá.ÊA)ƒ Gje%hJxè 'Èß—hÛ~bTˆúÔ Ü½µ¦7ÄXLÿï¾~mOÔ¦ì÷¶ ùÔö ,±-ò¦ŽWP\ªFøðÕÑI:d/¬ Ȇ¿Tbeotàƒ#à ,*eŽ@»¦e÷[KÊuÄxƒøØ‹F¦‚¨ã`®]ÄüKR^›‹D¹£< ”$#w剨C=E!2€`_L<;%‹ºddE,AÀ"ƒ½>æÕ¬¬=Øn†)»q‰¬-ª³n™Ïg~¹ƒ¶×';tWžu‡Ëgtë‹ì#Ÿ’U\XÅ÷ZIÄDå;{¶1ÉÕ4ÐÝÓê·¥5š³=8yPn*ùø¤—ðÅ:°ì“/À”T §3J”¦ØÖh;Ë :b íQKã1ñ +ÂèœíØ,ïm»ˆÜ䊭RjqËTÿÞLgîÁo6^޾Ñx!àŸâm ˆÈ UÐpâ»6G{n»n ùUî6r< ù…í•IÑeV­êc–ݳô‹1KJ YÙ4+iö3’)4›ë½n&§õÝâµMø%qO¸g&Ã\ä[q°Œç‡Pbð´~F=ÿ¿D=1ç£(mEj—wIÿ:ŒwÜOÚ4l·ÓYxåFÐ( ¥Sz. Ž(¤/øm»$ãÕ6’#JDŠìM•PôÒ?cIÑf§³ 6 •­¦™‘ËâIzpÎ\ Ÿ¸I"Š .M'оûÐ)øZI'/.§uqTõQQb^@šI VRWIÑ>ô±ápu¢KŸ—„ÚYiË À-;îèÍ K.¯&9“ß:âozgRË™ ¦°‹w«6²—ˆ1Úðïoƒ›Ë}ÃÇ¿^Òîõë5ב˜ *ïmSÞܦ³-7—Æ%©ßuúÝ`úAã¶8å}qÊfE§o¨è§~¼ÛɇÙ;S#…ï#÷ð½z²°Ì쮊Ž?*’ýmESÀ"ú¿'ÿïW@ž¬rp#²h^5àêÍäòvbú†@Z"¬ko(x/¹+¡ª”‹“õl“,þîqz!‘ÃGrËþQ±{Ušhž¨h¾~r‰±ÃŠðþT—sIúÑn‚†í”74çwÂü¶§ZcÓ³q üàp¿Œöÿá~YÀuê¼wXp‘¢LDð×¼05uÝFœBþÜÒ•:@òÛ»‚tè8Ñ4hO:¶)—¹ Šq©,YéÓhþ™B§à2i¶[¤1+RæUš©D%&(i‡Âºp Õ¬Z•y¤?í ¸ÑÔÖŽÙ VµÚ(K]›îÀªÔÄ%XCw¬Jx™BÇå8DÛsjÕ°ýbëÏZ% W…3ô#†`¾ºUЋhý6÷KÑ8@tdÊSþÕµ! ¤U‹×9ØjõE³ÅcµZ¾‰rÖôr M†¥&Å@ŠÙ‹Ý@^–ArH9¨akÕ"¹†¶@Û.†•ïhþCØ`aN«ñ.$°Ñ9f ¿5ºð—´âÛGͦUð·0\ƒGú±ß8PEà|äQ¼Í!—ÐIw ïNš*8AÑ΃®iXÄh¬³Kç(Ùdbà¬èY¼Ë«· e¬bUó1ó OQxY²l¯W3Uˆ²Å›1¢.76°º’…ÆðŠw‰²Óv 4æ8ïRß”MÇöm%ÔÁÎvdUC íÛIG.êÏd̬•®Q?Tßl ?ªš !7û3e3;8ÀÀ /IÖfQ'Mº]°‰®!…ÐÈà_ N¼;ØoÿîV„ «^SN©})ñ¤·¸ì….¹¼¯L@´D^Î ½hR”@ÞwZ4˜‹«E.À1cŒ³g3­›ükU ˆð@<€i“ý þy•|1§óJw°Zù©BpÙå@YX”¸±üí!o´s^*V^jVvw°_¤) :I0ûB8úˆ×°ù¯ûßÊŸ:ì~ƒ¶Q—XUáïì¯+Ô¬œí~+²’fîÉÏ}—ßBÿ[s´`˜Õb¥ƒ!e÷G°;…&k¨ ¹ }²è^Ü·÷ÿ 1ŸûÙݤr…Ph/µL¾¹U{âí69…X½Ö)‚jVb8Ë6K®Šµ+*AÌfRŠÀFÅКÎmw`âXµh`wA' ø:²ð” 8ÙwJ°Ãö¥“Ö™Üh¥}Wöå:À•<ÝH$?d¾÷#w H7’xõ`W’BŸ¿¨”®'îƒMœ?›%±}êµ2öI§E]»·<ú¯suÓQIÀªZ5rëÁœÌ6ó9ÆVÑФL<æX§ø ý<ʸs?ˆúYeø™Ò÷äMê uA¥B¶ ‚e…HÝœñ /Â;Sµi‰1Ý‚èX½”HßË&f!lQém´ âøÙ9Že$ŒªŠ$õ(¦Ì‘Á‡·¾ïºõâ ¨ŠX9gä~oâ—ý•©uЉ`“GÒej¹áciSë¼mŸÐÓøè2/X¾,·îÀ¡8¨&—¿v(ÜÍárÅö.ä‚q ü¹}àå4š@œ7ž8,ü<¹_é>Ç2‡æù°tî'Éç¬9Á^s ¶ÌÎ-Wh޳ Šû·Rë¸èÒÏè/E¸XeÌcÊ£r¸æKCršÔƒ¹ <}œÙz?3²á×uÍ£<~îP;ã±Óòþ–ßq·†SÆøß–€¯É¼$W~D>7VЬ\aÓ a{àòé¡ç=d¤rF ×ï$R=¢À©/åLWP±˜ÃP)H&Ìwpž[&p‰p–ÑÃc.è>í”J➎‡î‘–'yæf]¹;庲á”–ÚI—Ü8<^! ‹ê¬¼ôŽ~tEL¯!Ë6øwNKþW.¼ªây¥Á¶dÑí%«³‡‹3«/}BìAqM±öÝc9”* Æ…àÉ Ë¼C5j’ßÝ|¡ôµ¸c×BÚ¸ƒ²Ñ ŸQ—ëò‹o}9·9ç_8„¯³'#U+s'°V­ï<{i@·õ¹jÍ ìdKù½6öh¦âÛ/>9wÛX&¡=^ÑI–dSn“ù²vÖw— ’Š*¢êÌV·UÝŠ\zY® Õ»÷X¨甡 œêÂòC'Û³5’>^nQƒ§_…çÑ< ²xú¾nWÈ9i¢rŽh‹•ÐûÑVB_ÕÍ^«*Ov&VËVžûßbQ”Êe¯ëµ/ûÀ‹=,‹¾rPµë<³ã\W”[m*2äeF0³â$:ªª’ŽO˸ðaÌoî²N¤ ~&l Öë4ù-Aéƒ×‰w¾pñ?2Óg8_¢8÷X æ¢?å>ä2uHc­ÉýÐ׬¡áÑŽ~ 0tËÓ=#ã0¬ÞŠ­í¿9öûž®%<þ›“5|g ãÝ[.=9ËXAŒ£ÈÈ#ùCIÂäk¡à÷yœdTÒŠ‡Oš–ÚÞÁŽ÷Ì1dMºÔïg¨ÔŸ@—2"ûìgê 0!Q]€L‡>ìî *k\·þÛÔºçÀ\Qý<À#+ÚX÷qð ËÁŸÑ*,•’„Ù{÷Ò%—™`•P®V’b«ºAgÝ^X³ºûJ;ìñ͵ªÕK[òú2k÷¼ñwTÏÊÔWÞxgÝq÷Ú³î¿{Ñ}wzwüa8™aY؇ëÛ÷\ß ÃVÂÏg7aÓ'õø_MÏ?âk|G°ÿ{þüô/´¯_Zyquþ2+Û¼R*µ“ Åh }O¤Ë¿$¬ÚéÒ Ÿ·…;ÌaÈÞzo X>¾ùOn!5;)f¹ˆŠ„N¢ñaD:R›± Îh‘šÁd÷Á—cz¹IG/ ÿ±‰RSíN¯„5Þ ÍÔø,=êAÙ^Ç·!žQ§–*/CãýÉ ÑWg?å0ÐβÍÕXòçÀXµiFD€hô«ÝáÞópS#æn:ðý‹ÐÑ9&7ÖµiB@r:ûKG{q³þæRElð µßˆiìUµ•=:jhÉJkß½j†ä”0(¤éðÜ­lmÐ4_1°h­Áh×ñˆ5{¯%œÕÆÒ!ÉFELñ4©WvEÕ%¹Í{+O73’æ„ýªèÒ]*¹ÅŸ¯ ÏlºæIcÖQWÒU™µû‹MhP: ¥`ýB¹€<ô„Ï|Cu+ 6ŽhÇÎÉ*Ä YÅ¢ˆà&«B¯COž9Š0)GàN€7GùÂ;>idåÑV ¤A”†ë4Ì€kº O&y-¸|±alg|Xþ!Fi`’ªM¡‘H 6ã%ghèÊÄ";¯ cž‡sñ÷à«j£¦Áš8k ,ЕkHÛ¬ñÒÔ È¦Òùœ î]§'Ò˜§ø¢!BJMö’vá#¿ÔyXì/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="configure.base" ac_subst_vars='LTLIBOBJS LIBOBJS STRIP COPY_FLAGS RANLIB LN_S SHLEXT canonical_host_type OCTAVE_VERSION OCTAVE CXXPICFLAG CXXFLAGS CXX FPICFLAG FFLAGS F77 CPICFLAG altopath altmpath altpath xpath opath mpath subver ver MKOCTFILE OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC TOPDIR VERSION PACKAGE target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_path with_mpath with_opath with_xpath with_altpath with_altmpath with_altopath ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-path install path prefix --with-mpath override path for m-files --with-opath override path for oct-files --with-xpath override path for executables --with-altpath alternative functions install path prefix --with-altmpath override path for alternative m-files --with-altopath override path for alternative oct-files Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE=octave-forge MAJOR_VERSION=0 MINOR_VERSION=1 PATCH_LEVEL=0 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$PATCH_LEVEL TOPDIR=`pwd` ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Extract the first word of "mkoctfile", so it can be a program name with args. set dummy mkoctfile; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MKOCTFILE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MKOCTFILE"; then ac_cv_prog_MKOCTFILE="$MKOCTFILE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MKOCTFILE="mkoctfile" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MKOCTFILE=$ac_cv_prog_MKOCTFILE if test -n "$MKOCTFILE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKOCTFILE" >&5 $as_echo "$MKOCTFILE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$MKOCTFILE" && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no mkoctfile found on path" >&5 $as_echo "$as_me: WARNING: no mkoctfile found on path" >&2;} # Check whether --with-path was given. if test "${with_path+set}" = set; then : withval=$with_path; path=$withval fi # Check whether --with-mpath was given. if test "${with_mpath+set}" = set; then : withval=$with_mpath; mpath=$withval fi # Check whether --with-opath was given. if test "${with_opath+set}" = set; then : withval=$with_opath; opath=$withval fi # Check whether --with-xpath was given. if test "${with_xpath+set}" = set; then : withval=$with_xpath; xpath=$withval fi # Check whether --with-altpath was given. if test "${with_altpath+set}" = set; then : withval=$with_altpath; altpath=$withval fi # Check whether --with-altmpath was given. if test "${with_altmpath+set}" = set; then : withval=$with_altmpath; altmpath=$withval fi # Check whether --with-altopath was given. if test "${with_altopath+set}" = set; then : withval=$with_altopath; altopath=$withval fi if test -n "$path" ; then test -z "$mpath" && mpath=$path test -z "$opath" && opath=$path/oct test -z "$xpath" && xpath=$path/bin test -z "$altpath" && altpath=$path-alternatives fi if test -n "$altpath" ; then test -z "$altmpath" && altmpath=$altpath test -z "$altopath" && altopath=$altpath/oct fi #if test -z "$mpath" || test -z "$opath" || test -z "$xpath" || test -z "$altmpath" || test -z "$altopath" || test -z "$ver" ; then if test -z "$mpath" || test -z "$opath" || test -z "$xpath" || test -z "$ver" ; then cat > conftest.cc < #include #include #define INFOV "\nINFOV=" OCTAVE_VERSION "\n" #define INFOH "\nINFOH=" OCTAVE_CANONICAL_HOST_TYPE "\n" #ifdef OCTAVE_LOCALVERFCNFILEDIR # define INFOM "\nINFOM=" OCTAVE_LOCALVERFCNFILEDIR "\n" #else # define INFOM "\nINFOM=" OCTAVE_LOCALFCNFILEPATH "\n" #endif #ifdef OCTAVE_LOCALVEROCTFILEDIR # define INFOO "\nINFOO=" OCTAVE_LOCALVEROCTFILEDIR "\n" #else # define INFOO "\nINFOO=" OCTAVE_LOCALOCTFILEPATH "\n" #endif #ifdef OCTAVE_LOCALVERARCHLIBDIR # define INFOX "\nINFOX=" OCTAVE_LOCALVERARCHLIBDIR "\n" #else # define INFOX "\nINFOX=" OCTAVE_LOCALARCHLIBDIR "\n" #endif const char *infom = INFOM; const char *infoo = INFOO; const char *infox = INFOX; const char *infoh = INFOH; const char *infov = INFOV; EOF $MKOCTFILE conftest.cc || as_fn_error $? "Could not run $MKOCTFILE" "$LINENO" 5 eval `strings conftest.o | grep "^INFO.=" | sed -e "s,//.*$,,"` rm -rf conftest* ver=`echo $INFOV | sed -e "s/\.//" -e "s/\..*$//"` subver=`echo $INFOV | sed -e "s/^[^.]*[.][^.]*[.]//"` alt_mbase=`echo $INFOM | sed -e "s,\/[^\/]*$,,"` alt_obase=`echo $INFOO | sed -e "s,/site.*$,/site,"` test -z "$mpath" && mpath=$INFOM/octave-forge test -z "$opath" && opath=$INFOO/octave-forge test -z "$xpath" && xpath=$INFOX test -z "$altmpath" && altmpath=$alt_mbase/octave-forge-alternatives/m test -z "$altopath" && altopath=$alt_obase/octave-forge-alternatives/oct/$INFOH fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: retrieving compile and link flags from $MKOCTFILE" >&5 $as_echo "retrieving compile and link flags from $MKOCTFILE" >&6; } CC=`$MKOCTFILE -p CC` CFLAGS=`$MKOCTFILE -p CFLAGS` CPPFLAGS=`$MKOCTFILE -p CPPFLAGS` CPICFLAG=`$MKOCTFILE -p CPICFLAG` LDFLAGS=`$MKOCTFILE -p LDFLAGS` LIBS=`$MKOCTFILE -p LIBS` F77=`$MKOCTFILE -p F77` FFLAGS=`$MKOCTFILE -p FFLAGS` FPICFLAG=`$MKOCTFILE -p FPICFLAG` CXX=`$MKOCTFILE -p CXX` CXXFLAGS=`$MKOCTFILE -p CXXFLAGS` CXXPICFLAG=`$MKOCTFILE -p CXXPICFLAG` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for F77_FUNC" >&5 $as_echo_n "checking for F77_FUNC... " >&6; } cat > conftest.cc << EOF #include int F77_FUNC (hello, HELLO) (const int &n); EOF ac_try="$MKOCTFILE -c conftest.cc" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } MKOCTFILE="$MKOCTFILE -DF77_FUNC=F77_FCN" fi # Extract the first word of "octave", so it can be a program name with args. set dummy octave; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCTAVE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCTAVE"; then ac_cv_prog_OCTAVE="$OCTAVE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCTAVE="octave" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCTAVE=$ac_cv_prog_OCTAVE if test -n "$OCTAVE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCTAVE" >&5 $as_echo "$OCTAVE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCTAVE_VERSION in Octave" >&5 $as_echo_n "checking for OCTAVE_VERSION in Octave... " >&6; } OCTAVE_VERSION=`echo "disp(OCTAVE_VERSION)" | $OCTAVE -qf` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCTAVE_VERSION" >&5 $as_echo "$OCTAVE_VERSION" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for octave_config_info('canonical_host_type') in Octave" >&5 $as_echo_n "checking for octave_config_info('canonical_host_type') in Octave... " >&6; } canonical_host_type=`echo "disp(octave_config_info('canonical_host_type'))" | $OCTAVE -qf` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $canonical_host_type" >&5 $as_echo "$canonical_host_type" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for octave_config_info('SHLEXT') in Octave" >&5 $as_echo_n "checking for octave_config_info('SHLEXT') in Octave... " >&6; } SHLEXT=`echo "disp(octave_config_info('SHLEXT'))" | $OCTAVE -qf` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHLEXT" >&5 $as_echo "$SHLEXT" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi COPY_FLAGS="-Rfp" case "$canonical_host_type" in *-*-linux*) COPY_FLAGS="-fdp" ;; esac STRIP=${STRIP-strip} # Extract the first word of "$STRIP", so it can be a program name with args. set dummy $STRIP; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="$STRIP" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_STRIP" && ac_cv_prog_STRIP=":" fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi case "$canonical_host_type" in powerpc-apple-darwin*|*-sgi-*) STRIP=: ;; *-cygwin-*|*-mingw-*) MKOCTFILE="$MKOCTFILE -s" ;; esac CONFIGURE_OUTPUTS="Makeconf" STATUS_MSG=" octave commands will install into the following directories: m-files: $mpath oct-files: $opath binaries: $xpath alternatives: m-files: $altmpath oct-files: $altopath shell commands will install into the following directories: binaries: $bindir man pages: $mandir libraries: $libdir headers: $includedir octave-forge is configured with octave: $OCTAVE (version $OCTAVE_VERSION) mkoctfile: $MKOCTFILE for Octave $subver" ac_config_files="$ac_config_files $CONFIGURE_OUTPUTS" test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "$CONFIGURE_OUTPUTS") CONFIG_FILES="$CONFIG_FILES $CONFIGURE_OUTPUTS" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi echo " " echo " \"\$prefix\" is $prefix" echo " \"\$exec_prefix\" is $exec_prefix" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STATUS_MSG find . -name NOINSTALL -print # shows which toolboxes won't be installed " >&5 $as_echo "$STATUS_MSG find . -name NOINSTALL -print # shows which toolboxes won't be installed " >&6; } odepkg/src/configure.base0000644000176000010400000002206310570636775016635 0ustar marcoAdministratorsdnl The configure script is generated by autogen.sh from configure.base dnl and the various configure.add files in the source tree. Edit dnl configure.base and reprocess rather than modifying ./configure. dnl autoconf 2.13 certainly doesn't work! What is the minimum requirement? AC_PREREQ(2.2) AC_INIT(configure.base) PACKAGE=octave-forge MAJOR_VERSION=0 MINOR_VERSION=1 PATCH_LEVEL=0 dnl Kill caching --- this ought to be the default define([AC_CACHE_LOAD], )dnl define([AC_CACHE_SAVE], )dnl dnl uncomment to put support files in another directory dnl AC_CONFIG_AUX_DIR(admin) VERSION=$MAJOR_VERSION.$MINOR_VERSION.$PATCH_LEVEL AC_SUBST(PACKAGE) AC_SUBST(VERSION) dnl need to find admin files, so keep track of the top dir. TOPDIR=`pwd` AC_SUBST(TOPDIR) dnl if mkoctfile doesn't work, then we need the following: dnl AC_PROG_CXX dnl AC_PROG_F77 dnl Need C compiler regardless so define it in a way that dnl makes autoconf happy and we can override whatever we dnl need with mkoctfile -p. dnl XXX FIXME XXX should use mkoctfile to get CC and CFLAGS AC_PROG_CC dnl XXX FIXME XXX need tests for -p -c -s in mkoctfile. dnl ******************************************************************* dnl Sort out mkoctfile version number and install paths dnl XXX FIXME XXX latest octave has octave-config so we don't dnl need to discover things here. Doesn't have --exe-site-dir dnl but defines --oct-site-dir and --m-site-dir dnl Check for mkoctfile AC_CHECK_PROG(MKOCTFILE,mkoctfile,mkoctfile) test -z "$MKOCTFILE" && AC_MSG_WARN([no mkoctfile found on path]) AC_SUBST(ver) AC_SUBST(subver) AC_SUBST(mpath) AC_SUBST(opath) AC_SUBST(xpath) AC_SUBST(altpath) AC_SUBST(altmpath) AC_SUBST(altopath) AC_ARG_WITH(path, [ --with-path install path prefix], [ path=$withval ]) AC_ARG_WITH(mpath, [ --with-mpath override path for m-files], [mpath=$withval]) AC_ARG_WITH(opath, [ --with-opath override path for oct-files], [opath=$withval]) AC_ARG_WITH(xpath, [ --with-xpath override path for executables], [xpath=$withval]) AC_ARG_WITH(altpath, [ --with-altpath alternative functions install path prefix], [ altpath=$withval ]) AC_ARG_WITH(altmpath, [ --with-altmpath override path for alternative m-files], [altmpath=$withval]) AC_ARG_WITH(altopath, [ --with-altopath override path for alternative oct-files], [altopath=$withval]) if test -n "$path" ; then test -z "$mpath" && mpath=$path test -z "$opath" && opath=$path/oct test -z "$xpath" && xpath=$path/bin test -z "$altpath" && altpath=$path-alternatives fi if test -n "$altpath" ; then test -z "$altmpath" && altmpath=$altpath test -z "$altopath" && altopath=$altpath/oct fi dnl Don't query if path/ver are given in the configure environment #if test -z "$mpath" || test -z "$opath" || test -z "$xpath" || test -z "$altmpath" || test -z "$altopath" || test -z "$ver" ; then if test -z "$mpath" || test -z "$opath" || test -z "$xpath" || test -z "$ver" ; then dnl Construct program to get mkoctfile version and local install paths cat > conftest.cc < #include #include #define INFOV "\nINFOV=" OCTAVE_VERSION "\n" #define INFOH "\nINFOH=" OCTAVE_CANONICAL_HOST_TYPE "\n" #ifdef OCTAVE_LOCALVERFCNFILEDIR # define INFOM "\nINFOM=" OCTAVE_LOCALVERFCNFILEDIR "\n" #else # define INFOM "\nINFOM=" OCTAVE_LOCALFCNFILEPATH "\n" #endif #ifdef OCTAVE_LOCALVEROCTFILEDIR # define INFOO "\nINFOO=" OCTAVE_LOCALVEROCTFILEDIR "\n" #else # define INFOO "\nINFOO=" OCTAVE_LOCALOCTFILEPATH "\n" #endif #ifdef OCTAVE_LOCALVERARCHLIBDIR # define INFOX "\nINFOX=" OCTAVE_LOCALVERARCHLIBDIR "\n" #else # define INFOX "\nINFOX=" OCTAVE_LOCALARCHLIBDIR "\n" #endif const char *infom = INFOM; const char *infoo = INFOO; const char *infox = INFOX; const char *infoh = INFOH; const char *infov = INFOV; EOF dnl Compile program perhaps with a special version of mkoctfile $MKOCTFILE conftest.cc || AC_MSG_ERROR(Could not run $MKOCTFILE) dnl Strip the config info from the compiled file eval `strings conftest.o | grep "^INFO.=" | sed -e "s,//.*$,,"` rm -rf conftest* dnl set the appropriate variables if they are not already set ver=`echo $INFOV | sed -e "s/\.//" -e "s/\..*$//"` subver=`echo $INFOV | sed -e "[s/^[^.]*[.][^.]*[.]//]"` alt_mbase=`echo $INFOM | sed -e "[s,\/[^\/]*$,,]"` alt_obase=`echo $INFOO | sed -e "[s,/site.*$,/site,]"` test -z "$mpath" && mpath=$INFOM/octave-forge test -z "$opath" && opath=$INFOO/octave-forge test -z "$xpath" && xpath=$INFOX test -z "$altmpath" && altmpath=$alt_mbase/octave-forge-alternatives/m test -z "$altopath" && altopath=$alt_obase/octave-forge-alternatives/oct/$INFOH fi dnl ******************************************************************* dnl XXX FIXME XXX Should we allow the user to override these? dnl Do we even need them? The individual makefiles can call mkoctfile -p dnl themselves, so the only reason to keep them is for configure, and dnl for those things which are not built using mkoctfile (e.g., aurecord) dnl but it is not clear we should be using octave compile flags for those. dnl C compiler and flags AC_MSG_RESULT([retrieving compile and link flags from $MKOCTFILE]) CC=`$MKOCTFILE -p CC` CFLAGS=`$MKOCTFILE -p CFLAGS` CPPFLAGS=`$MKOCTFILE -p CPPFLAGS` CPICFLAG=`$MKOCTFILE -p CPICFLAG` LDFLAGS=`$MKOCTFILE -p LDFLAGS` LIBS=`$MKOCTFILE -p LIBS` AC_SUBST(CC) AC_SUBST(CFLAGS) AC_SUBST(CPPFLAGS) AC_SUBST(CPICFLAG) dnl Fortran compiler and flags F77=`$MKOCTFILE -p F77` FFLAGS=`$MKOCTFILE -p FFLAGS` FPICFLAG=`$MKOCTFILE -p FPICFLAG` AC_SUBST(F77) AC_SUBST(FFLAGS) AC_SUBST(FPICFLAG) dnl C++ compiler and flags CXX=`$MKOCTFILE -p CXX` CXXFLAGS=`$MKOCTFILE -p CXXFLAGS` CXXPICFLAG=`$MKOCTFILE -p CXXPICFLAG` AC_SUBST(CXX) AC_SUBST(CXXFLAGS) AC_SUBST(CXXPICFLAG) dnl ******************************************************************* dnl Check for features of your version of mkoctfile. dnl All checks should be designed so that the default dnl action if the tests are not performed is to do whatever dnl is appropriate for the most recent version of Octave. dnl Define the following macro: dnl OF_CHECK_LIB(lib,fn,true,false,helpers) dnl This is just like AC_CHECK_LIB, but it doesn't update LIBS AC_DEFUN(OF_CHECK_LIB, [save_LIBS="$LIBS" AC_CHECK_LIB($1,$2,$3,$4,$5) LIBS="$save_LIBS" ]) dnl Define the following macro: dnl TRY_MKOCTFILE(msg,program,action_if_true,action_if_false) dnl AC_DEFUN(TRY_MKOCTFILE, [AC_MSG_CHECKING($1) cat > conftest.cc << EOF #include $2 EOF ac_try="$MKOCTFILE -c conftest.cc" if AC_TRY_EVAL(ac_try) ; then AC_MSG_RESULT(yes) $3 else AC_MSG_RESULT(no) $4 fi ]) dnl dnl Check if F77_FUNC works with MKOCTFILE dnl TRY_MKOCTFILE([for F77_FUNC], [int F77_FUNC (hello, HELLO) (const int &n);],, [MKOCTFILE="$MKOCTFILE -DF77_FUNC=F77_FCN"]) dnl ********************************************************** dnl Evaluate an expression in octave dnl dnl OCTAVE_EVAL(expr,var) -> var=expr dnl AC_DEFUN(OCTAVE_EVAL, [AC_MSG_CHECKING([for $1 in Octave]) $2=`echo "disp($1)" | $OCTAVE -qf` AC_MSG_RESULT($$2) AC_SUBST($2) ]) dnl Check status of an octave variable dnl dnl OCTAVE_CHECK_EXIST(variable,action_if_true,action_if_false) dnl AC_DEFUN(OCTAVE_CHECK_EXIST, [AC_MSG_CHECKING([for $1 in Octave]) if test `echo 'disp(exist("$1"))' | $OCTAVE -qf`X != 0X ; then AC_MSG_RESULT(yes) $2 else AC_MSG_RESULT(no) $3 fi ]) dnl should check that $(OCTAVE) --version matches $(MKOCTFILE) --version AC_CHECK_PROG(OCTAVE,octave,octave) OCTAVE_EVAL(OCTAVE_VERSION,OCTAVE_VERSION) dnl grab canonical host type so we can write system specific install stuff OCTAVE_EVAL(octave_config_info('canonical_host_type'),canonical_host_type) dnl grab SHLEXT from octave config OCTAVE_EVAL(octave_config_info('SHLEXT'),SHLEXT) AC_PROG_LN_S AC_PROG_RANLIB dnl Use $(COPY_FLAGS) to set options for cp when installing .oct files. COPY_FLAGS="-Rfp" case "$canonical_host_type" in *-*-linux*) COPY_FLAGS="-fdp" ;; esac AC_SUBST(COPY_FLAGS) dnl Use $(STRIP) in the makefile to strip executables. If not found, dnl STRIP expands to ':', which in the makefile does nothing. dnl Don't need this for .oct files since mkoctfile handles them directly STRIP=${STRIP-strip} AC_CHECK_PROG(STRIP,$STRIP,$STRIP,:) dnl Strip on windows, don't strip on Mac OS/X or IRIX dnl For the rest, you can force strip using MKOCTFILE="mkoctfile -s" dnl or avoid strip using STRIP=: before ./configure case "$canonical_host_type" in powerpc-apple-darwin*|*-sgi-*) STRIP=: ;; *-cygwin-*|*-mingw-*) MKOCTFILE="$MKOCTFILE -s" ;; esac CONFIGURE_OUTPUTS="Makeconf" STATUS_MSG=" octave commands will install into the following directories: m-files: $mpath oct-files: $opath binaries: $xpath alternatives: m-files: $altmpath oct-files: $altopath shell commands will install into the following directories: binaries: $bindir man pages: $mandir libraries: $libdir headers: $includedir octave-forge is configured with octave: $OCTAVE (version $OCTAVE_VERSION) mkoctfile: $MKOCTFILE for Octave $subver" odepkg/src/daskr.diff0000644000176000010400000000227211042711462015734 0ustar marcoAdministrators--- daskr.orig/dlinpk.f 2008-05-19 11:26:08.000000000 +0200 +++ daskr/dlinpk.f 2008-05-19 11:21:57.000000000 +0200 @@ -760,14 +760,24 @@ dnrm2 = zero go to 300 c - 10 assign 30 to next + 10 next = 30 sum = zero nn = n * incx c begin main loop i = 1 - 20 go to next,(30, 50, 70, 110) + 20 if (next .eq. 30) then + go to 30 + else if (next .eq. 50) then + go to 50 + else if (next .eq. 70) then + go to 70 + else if (next .eq. 110) then + go to 110 + else + continue + end if 30 if( dabs(dx(i)) .gt. cutlo) go to 85 - assign 50 to next + next = 50 xmax = zero c c phase 1. sum is zero @@ -776,13 +786,13 @@ if( dabs(dx(i)) .gt. cutlo) go to 85 c c prepare for phase 2. - assign 70 to next + next = 70 go to 105 c c prepare for phase 4. c 100 i = j - assign 110 to next + next = 110 sum = (sum / dx(i)) / dx(i) 105 xmax = dabs(dx(i)) go to 115 odepkg/src/daskr.tgz0000644000176000010400000021100110766453003015626 0ustar marcoAdministrators‹êTÚGìýiwY–0 ÷çü±î‡·@ a Ùͳ–…„Ø–ê®»ž!™N*Ù©þõïžÎ'ÙrVVuQ•CœyŸ=“4ÿmùê?~ꫯ7Í&ÿ}íþ•×$ðÍëƒfc?©ÿG=i¼?QóçN‹_ù*]FÑŒ¿,îÓ¼ü¹M¿«…¨¿ÿ$¯ ÿ„þÔnθ¯êÁóOêý×oïüö÷›ÿý!›ø¿üü#z>¾^|wûèè¨=:F•agGýÎ_ãhGWðÿÁ°{ÞOð\uûÇq4_ôâ¨ÿþBýìÀÝ£îüôùbxG½ágxXÞwáýpÐÂ7ôïiû0Ž#§õ:ïã?§Ã‹‹qõ—Ã_wvvÞw>tûÑ`xÑ»øð±É$é§açSwÔ½èG'ÝÑøbxE•««óó£#h ýÕõ·IZ´Çèó°;wúðµü–$uøíðK:¿Ë&ÑÓÃrzŸEéòîñ>›¯¢é<:žt΢›t6Ë£ÕBv¡¦š7’7Qt¾˜Lo§Ð>[.Ëh™­—óèÞþO¶\äðîq>Æ‹èf¶È3xw—­¾dK·—öd],‹U4™.³›Õt1«‡Gšm‡´8¨7“·fÚé俈iÆ0ÃË>>z¼^Ö`öÐh$­šÐ* ξNsh•¯Óù]´ÊòUŽmà"¬2ì&šûõh/j¾­ÿ',g±œdËlB½¨ „íh•«y”ÂÐØatÁ7ý†}ËÏiŽs{\ÉT^×ß$ €Øßóö åF–r?OïÚ_k0¥›e¦–•¼ê|Wþ»*=}¨ïstBqt;ý:¸~¼Ã¥Œ;çƒFT99ïö‡U˜Ôlñ-‚³®Ä(|@Hé_Ô ‹¤Ý ¯Ï:W§G#€•îñqgØé»íÞ«vïCçý°ÝP}ß><ûÜÙŒôŽ/†ç{íQììô}>èu»c§Çht5‚ùÁí:^õ.>EÝqgHýÐ4ÚÇ'C˜EÔ›Î'i4¬Eƒlõ?‹Ù$Æ7Ù2ê×¢÷ËÅ·9ܼY:kÑ Î–Ó›/ÞC‡ð#tçu¸¸˜KþÒY4º™fó›,þQg~7gÙ.óÞ~òÚ뤗~[âÃ0ó¯Ùò¡¯úé¥×‹eºZ,Ÿ¼FƒœÂûÅïÑÛú[ÿt?qtØŽÞ4› íÑàãpp1<0þ2Í£›Å$‹òÅì+Ì2ò§ 8ZÜÂ5º½À¯¦éìU:»Ë®—éô&rÇÈþþHS̱ÜJÜ‚û¨°…*«ø)~úK5jEõ(öxÌØS˜ÉýõtžòÕ½Þ§7¿}K—“èÈÌ„~;†1g©×KåýÑq5ºܰ˜äxØã—Å6çömÍ`ÿXÉaÉÔÛtð« ‘¨2Éæ€uàd¯¡Ï*¾9[>Í_£ÊÎfô5“k¥_´¯°÷9v?%ì0Y<^ϲèúœâ×Ðbïe^t¤GÑá°;àk“Ùù˜§wÙ¯ôÞ»Kß÷:@ :‡„ø+í½“øbïoUýdîwgÈÄ U¥_…,="BDD©o«LŽ*;º¢€ð»"‚ô–é R@úØ–7Ö>y„!Ž0tGè\Âï. *kè ôgV|Øîõ¾›s;eu ÒQô×Ç|5…[øí `˜è>}Ô¥³’èú‰îÝÖt‰GË Ø[:´¤ê¬Èž=?$ïpt˜¶í\€vìWØg¨áÿ8‹yzO· ðPJ Lp³dÚO‹ÇÈ_|N|G“ìŸÇŽ–Y><‚»}œ3ÍÖ¨"Ø‹`™ÜÄ7»Æ €ÓþµÛ÷o¥ZÀãý5 lèÎ`0¸¥ø“Óɺ wró¸Ä9D_ÓÙc¦¦´${Èàø!¸„¯érš.ðôœAh„t¹„ã¿YÌWétΣi|hòa1'F‡±êG¿ê¬¬àF¦_ mi¤­ºÎ7<^g{ÕÆ¤ÑÃb k‡g R3søyà,½z1é^àa ©wpF¼„Gdºv`6÷óé ðZЬj–—ÊàZœ› wêúDŽ7ÆI†{Y-f€â‘&¯ž€ŒÞ§«åôw`õ–7À¦Â7+Q>ýŸ¬ŒuˆˆÿÚs?]åÄ`XTi¾˜»D‰©O-ØQ?ºF•pÂ*šeÈ6겑tÓñ¢›ÓÏ€jýÝ •e´'G¨L¯iGhÆðõŒ`!8"säzò¨»8[;Ï?UÍW÷»dñZð¡á©¤7puàÃ쉚~›æ_Ü“Z-‚ýàÑ{MIÂv’\ðöÏ÷z±úå0M`êJÎ$Êf¹iþj߆OLAƒ+-$˜‡Å’ø÷o_ÒUxC&ŸLõJðlïó)v±"BEÙnL€•˜d4ì¨ì[´Jô–ý¾RxþWüGšµa‚p€ßËßän™•U“#•ã$”Q‚pì)4¦vÂÑxŽ(Horƒþ|œ©±`Tš›ÚêÂ< ϵëÏuýVoœkwí\»Ö\‰Ö#©W ø¶Yæ½Å‹¥æþ.X®"êœ*Þ…%Àu$J\‡g{­¾eÙŸZ’D VFiï`Lš®Þ0Iø ²%ÕÎeIðû÷’{¼„kI~eñÀbÌì©Ê Kg7ˆwàŽœ¦7‹ëiê³áòªÀö!‘·¨V5š¤«ö÷+Ê,½áöŸ4Øãל ÄÊÚqKœÅ?gípm×.×ëÎOÏezK]äÙ ,L=R%me`°|x\> ΃yÑy2e#!.Ø‹?0í ]³ìvEbÉ@ê@S&‚CˆÛl ®—¼2ð„€~¦È#(¦/†ÓÊ8¾Š¯þREš‚KCUò/á M—¤„!Æ .Ü’îJMfJS¢Y†Bƒ£îéw¸¡(h (÷KÝ%ÅRÇÛ°”¡‡7«FM må’ÑÈ|aõlCž…¡ f„"5_í‡4GþkòxÿÄkÇÃ*–¤ ›š•2[)„þ±Ö¤•qZ¤v›ÎQöçýg‘âDà¯Óì›pŒ°G"Ž .ÏñÖ]+IâIú·,é#qÆ.ˆ•‚$<ÀÝ}‰n#hØwôZá(°\Ð|¸¢]{ú ¾eÅd}B^>§Gøgþ…TtdSBGØÍjj +ºƒyÌ„'`£jŠ$|åîò/‹ÇÙ„ù—y>…)ÎW¬Y!õžÂ 2°ES‚‘;Vãr1þò¤zÅnrدüö ÖJE]Ðza&'‹ol7 a†WSch££ýmNj1¸÷éøªÏG¥/éW÷üX;‰L×ÞÀg¦ùù$p®°ø¸@¨Ž˜ðppyo–ÓkÆÝÌij’±&²p ¨Eì ˜[âYt»\ÜGcˆë'­DH¶%A¢ÑÝ,²ÛÛé ¡.™åÀ’/YÁ–#ÛÈŽ¢¿ ])þ‚ƒ*‰îQj"& €â1$ßátVKEÜïQË1ÀS\.~ŸÞ#ñµà¹˜óžõzJùôz=Ô6ˢ߲ìAdëf øZ üžÃ\Ãé/Á¢|öûP‡ÕÄÝùÀCX¿è+4ÉýÿL£i©D¤~ø¨ÝÑà$@MǘœÝ|aþû`!H˜YnºA|’§7 Ç ¨kèõfEF¾éÝ\ŒÆŒ!Ÿ¬àHVpȳ™˜â6Hq:Zå=f&™¶ƒ¥bk.ÈbóÔÿWœL¾®y8"„3!ÉàZɃԂÍf´‘ɦ]–E ƼE†„L8œ2ü=~IîF¶xÌe÷H¨¢.®³›u+°>Bž€$Öå{ Ò€ÐÖêëÇE®9"þõ5æÊŽ×í@²Ú‹>Ÿ´ÇÀHFGš¾N:Ñqw8³9 ¿§uíxæ‚ÞN—@®‘X©) ‹ôç·ÄJ²¢“&·J—+²d ß8Gq‹´ò÷5tXH'ZZbý¿ž=ÂX±)Âé¯z,ÝÃÚGu&Ò>Â@ÅDT\Z\¥ëù°ˆamf®ù39âéÿh‹/~+3צx„g[¶ŒÒkÄ*¨F&Ýq:_Ùídc˜Í­©=6¥”,ÇÑåX¢¢1ÊËrìÁ.*®ñððno§7n¿EJ6c¬:]¹6¯M&v«¡1NñÝÒ YšÂ-ÜÀ"Õ~ÁB¥%ÈÆ¾¾FP«¹ëjζun³›·u´1€‰Ôz†'ƒ‘ NGo,N<$ðÁ.ל™…à—Ëœ’c÷¸Ð9ãÔ6­hµ»¨ŒZ ûbÖQ™š­fÚÑ!m¬Ò¸©cg'­` Œ(mN®Öäð„dKæÅeŽéºà6hïªÃSâ¼àò-ˆuY,µ™ Næa+½,ºQbòŒ* ž¸­E8z¨EÉAÓñlè/VÙ¯,lLÑ „¬ðJ°)#ÔÉâÛu9{ÈÑÃ0×Î,ˆyÀ£^,G¬Q1¡aQXÛët·¢Kgã(­ngé—tö Õì¸H¢èEf_‰¹VÑxÀ#7A‡†ùú µ&S[ó\Éâi!Ïä‰;¥˜A¾"iüÃ"ÍïÙ»8ŠC½·¢½{OeFÒ 1Ü©@…8ëY{ˆ›X!áElü''j9ˆéÐCÙs:¬¾oè´h>)O–‹™’+Šæòt h&£1÷¬²hDo¾Ë<ò|£ˆš›Õ Ž˜;§]Ã;õ¤´_¶—…Ü\Ü#×—a² G‘;æ•ÁlØßƒo îLR¯('Ÿ XñjÏêEÁ{dMYS«@=WcâHʨ¹ …cÛ7Æ êjÞÙh¾Oâ àQ›B3ò5ÞH1X§+½&¢ ¶«}èÔ,ÍJ±Åܱ§€vœ°ô÷•qAoŸωªqP¯Œ·ƒ7ˆè9eœ_ÈÝÁõr(L²Æß¢3S/!_Ú<ƒ•œïµñ=ë .± “_ãßQ¾ÊB/ëV­5â…UºñWï‘ȇ fz·ôÑ#\1~À›I¦oêºE7+¥”N€AÈЀN®V'jUû­ÆUöõ‹>¨~îñÏ0óï§«•öc‘×X;hM¾²|î쾫³·GTôÚÌÅô´"'œÈøâF>iS!ô‰7ÕA7_¦“?ˆyŒ-nžØ¼¤|-bÛ(np>¡r·=uÂ$«Ü.<"G$Ä…äQÅíÀ~bO89T£WqÄ.)ün\\T‡úR¬pªŠJ*¡]D6íæf±œèù£¾Äá¢Óé½-FÏŒ!ÏU¹ÛBWÄDg@Zs‘#íe®xfË숤“[òÚvnIܹr}r‘¤Àù óã_\㊤y¡‡%:†p[á‹òÇ銼JD siºïŸ:é^B|V.Øà•£1Ñ?ÝÞQ9–•³³¬È¹A‹,Qó îGž.Ÿbä$WË) bOÇø^ØhûrOð˜ôT÷šÊé8âQ)‰—•u@ì‰ÄXÁY9ž•ò\ƃXk P/—‹1iºzŠx§D­`Ó¥{بÕv/ŒbE‚¿ÎžŽË[CÅ34ÌkuÊÈ$‰W'ó-Uá=Š"¿›^V‹ÙÄ!Kk' '(3Q¬>+¿çO„ —Ù;¦éDØj˱©Zô‘ÙúÆ6’êõ|È×]¼ùX¾w ‰#ì+‰‹¸]%ÛÞŽÚØêv¢ êRµ¨Ù¨#6$到Ád•&ÎççöÁàœ4AX¡‚Ó&(-(R%²ô6Z«âvÄ*ÏÃÔ9%þþˆñÀ\ "ÈɨC¸H'"Nf P&À® ÂýãLd®äÄ„‡?×í$îÂpV´‰†#Ïæ¬°ÑçD0#JT£:º-ø*ê É5u×ή¾J4~ß ®? ¹ú˜xEÝœAÒ Ò’Ý*§9µZÀ‰ò ³GóRkï5_Àc$ •à†Ð%^÷°_f„2]&a2,¢²`ƃÔ5ž½¿é Üôhźj!ÖÔ· íeþ¹SÏ>ˆ›RðÙD×P èZX_¢b"VŠd r‘¥{TûXˆ‰›/2Àß§×Ó KqT Eös‰œãq¨ ŒÅœ3bCÀÐ^Š gpÑìù®f½D4Ê ‚^,N! £úÄÓ¦ 8›\Qî0ÉæaD$„¨}¾ÆŠuQ>W¼§e+Dî–èµ?tQ@~Îg]Ó€`öÈõ»pxG—o$Y2û=À@úT|˃ËDÂÆp!RD(8¢'(aŠšåñÝ-À121œqƒB½øã±J¹às‹—¸Ë (ê”õ•Žq@o0’ݲ-a¿“èuìk#×ø†™'"ñäå3-,Åð_²ñ|Mµ9nöº)G W[nØ$t/ešGnΚò3«nuµö9ö«¢¼iœƒÜxc¨u"­ƒ º tpóÉ,ÛbûýyˆÌM›aíp,lá+€¡RFÊl¥Òy-3¢„gŠ¢ýqFÛL.H~#€i4„g+l¤2kºŒœðfȈªan5oKãïŠR‰xBœ-ó¯Qþl–ØfÅ,ŽÛJà¿ÊĬ„›ä÷A»WÐ:OÔ²k­òÂ7´ºN±DJ°`S—êËÄçhûq„}>(%.´¬Åï‚=H…;'v©Æ—âíŸÚjºM¼ì?€ xH¶ VTq¼žr?”‘¨;k™×ZríÏ‚„¢pà¬ÆL•Pgѱ[©« X3h/3*HƒxYCà&‹V?˜‘ò|@8OçéìIIÊñf´_–ÕTK¤8+t¥°|†£Ù4_z¬f¶ËñlóÇ{ØÛ-Œl°sƒc GÒž‰ÈÂèx7¸µKŽ0%çVØ‹ÕÂTBwPQÐ9”NË0vi Q¥kç–ÙŒï–PUÿW<`{è¯Ó÷ÎôcþH§Q¶AÌDÃÞ,ò‰n€:ä€ñi{L€Ñ×E‡æ<€h÷ø k±%Ð Þò©­ž4Ä‘ÁÆÞø½âm—Ùº  ðÉd%Ü­¿š[â¯æfüe<ô•«€Ðgm{à°Íq­E!\öú‡q™mé_-Çkzk»¹Ê}|f‡Ýæ¢ QÑÃÓ ¦*r =r–÷¬ R†'D9¹r¢2`>)½À$¨‘Vgš{ºšXÑòÔw.¹~7ÄÁn.3r‹ËܲmE~Ÿö˜ðô}Í9þÞŒ@Ä\,Wx!´3fD‘ÙïÙ â%êu¨Ù²¦ÜsØŸdàt:)èþóœ]£ó^TA=[²ÓæùǨòøð€áð “Ñ£(÷aQ =ÎÉY>®*ÿ]%&¤Îå´ö`àÚ,«Eÿͦ»0t@Q—‰ddÚJâF —:Æ`D\ÿ#@ÚyOÍYy+^û%Š–I-h…½Ú&„[+#>2pµ~7Z¡~|ªöN¼Î²ßofÒ½­¥¾–îG¤½©ì& ^@먄QD/–¿åÊO2­~`çvv…#I’– Þã¤J>‡s ÁÝ\­\…=¦1í¹#Fê#ä˜RáÌM¨¡v-ȦzÖäÐyEóAÇ dV>ÙbÅU…B½Áë1«½ëú§›92ÆÃeø¾(&[Ri]®9Ùyô§ \`:!†uj C+ã3ŠoéL;‡àO´ÇÉ!³±I`ùY¨¤%t|œ$¤(ÆÊ4­§*£7|;!úõZ¥ûØvôÛà‰Êy¯j!‹ÊùÇp |Yø5E,”>­" Zç!Õ˜ýLžù¤ýoö‹­WEÏ<ñ;ÅTtP»rÄ)LžôYÓÿÁ˜ýEÈœ•~]L9†vº$TPûÝݾCîöŽDä”r¯M.È߿ɴ‚âÆ¨ùnÇÚ½Ù’µ{³µhzrÞ¾Üæt‡rrÐ/5 Þ[<=;-@j³J‹``$X¸p‚ØžU™9*û2í)¼ÁôæqF©–í1Ÿ"ך  ù&]³ÏºézQd l 6rÙìA¬?Ù×)“<Ë"R±š(0cÑ5R&|ѹ)à*óìx&`½Ý°ÞnXõíÁŠô~Ð Tï¨Ð¥\H,)v0 §“#3Ò‹©Ö×OF_$–o…]$l„ãÆ/†GA,0E=žväkÖ˜¥#×lnXc ”½¨©éH—†Sb_Ÿ q4æÞ n„ãTDüŸþ†™4ôm6„Ük^Ð…£¥.´L˜Cå…òûfm3ªÝÒáj;àms;`{·%°½ÛØd[S)8iº¤ŽPg£vú•82ËÁªD™¥uЫããJGv`öÒ˜/æóì.˜™¥ð??,ò)¥Cˆ•»ƒÂ?¹¸‘„W6ì²<%‘æ«/Ë,Óño´˜@Ð}ú5ÎPókXj«Ø9nGùƒ xó¡Oò¡Uº×”E°IáºÍÒ«Áƒep“Y»„ŽStÈ+Iàw´ïvDÖ5µ ÁOÃ×ìDâ™Á>8´4f"¨+ßå6"â¡ð¡ë,g×¶"a1¬½VÎ6èîÎñb1šNßô9“â"µâZ(e Ø¿Ìð,:RêS\<7Šcòõ¤Y[¸vè{Gbå0ØàõÚ ðƒ‰óeu¤E…@Y ¿†îcÛ.öý.öÍ4<$b½‰P;cÆwVÇ€¥$¦P'̺bìù%£1MÈ£× ”È?=Ô‹{?בbWÕyfáU¶ïGSК ÉÔw»¸À]ò¿ªÀ% ’ïp½@m¶ãíÚîÆíѸ#¸EÑ{ãçôÕu¢hv7×#;äŸ#ê˹¤G0‚}xôÈF&ŠII¦A5$k­×…ܾ§ôØ× !¿ å’ÕPœÑç>ã%*\•Q, Jë0]ÐöQsQTÁÑ"š 4"À%\ýß¾)%¬‘XL3j‘ê b4CYx¬d ^Ø›’~‚„õ…uÁœb}3ºþò'&‚y5Lÿ8í W¶k‚ñ%×q5¿µƒËBzåJ¾”è¤XÌÜÜËô‘›XVD…jwD '‰3”†bb’ª„ˆX[D.ô ¨[ÙNˆúlAJ}Â|ÄŸhúcvX!"¿fADDŽ¢^/`/ï$‰d}øNªaù$–XoœD‰ìQ(ŽQ¿¬Ã®˜ûäÁ’ùœ;¥‡²5š‚lÒ‡t¬Î~GŸ½éª¨?À—òK6éF-¤V­mMÂzÝ£ #ù3ˆ_¶ègÏíg@7A€úFœ|°ˆ¦ØŒB[ƒI=± Òdpcn‹¬G‘ ‘Çbç÷›ìa¥ÑƒJa t³^ø^aÖ‚+u*ͫŰA'X° ~'˜3¾º%ÙšU:hÍÖ†0QI¢Ì•ÞÚȧAøÔa¬]«dTð»§W!«M (£<‡q—Í‹|«æDZö󤵯©S[+åG˜}üÅí¹[¥2^nBŽb³¤{F‘¤Pñ’Õt,Ök÷æ²t,ôÒˆÙ7!'QÅ™XŽ¡~ ö”#èyû²GgçÌì ˜v½n ΂AF´ñÅ»õ@±f͘rä!U$ù’¨·Tú|G ¥Ndb`Uc?xQØžéRõ' Š\|Ú‹ nl¢ÒYÆ_•ÑI‡ ržŒfrõT¨?R?é´3™3­e çÝ~¥S«Â=;Àfn|NJcÆ)‹%œ„ƒª“½ Ó¯[r†a•1ìi;³óEö53žû_•t ¸È¤–*žˆ;aòB@û$ºÉàH8 ÕZÀEž„Š” yàŽl¥W$Zº‚x[l~0)>fÖW¼‹Íçp†…9y€Uù~~¾i ]úýD¶Ç²*qœ‚IˆZè$ÍóÅÍ”<^<Á†§6(N‰ã#Œ± ѯŽâÂÈ+R²ºÍÉ÷þ) ã¦f¤,ôb9Õ·2$N{À\vƒèžÒ¢´X·Ã8™KÎÛ”vÒóžj+¶“ò­ÛJR |ÜÃHpò™»å2´•–I³è0+f$'™£ä#d°“·ÏI;:(bS“.øqŽ–e;%fU%A’ÄGÅEØõBrTÆ»—° ÷‹ÀžÓýª gX K´ÁÛa®¦8)C,ù •má]¦Ú弬< ¾p-ˆÙsN)f…‰IHK·µˆ4ezä—-ZK¢»äÔ—#٠ˆDpf¦·†Q©…fU¨YÎ5IfOQ°„Jp§g±Ýq•úÚù§³ÁÛn®öõºZzý–^?¢µ¥× ¨ny)?¤¿¥×+qùdž¡É-çþÝ—ÖÕ®½p[ë~Ÿ=ìšmßNO\ÚnºË¶Ò¿ 1TJ¸1œÓÓ@µœci|«æ“€¦_²Çå4_¬2Ò°ª"1$=kT&\O*;‡-ov´@i£b ÔÇáÂ’©½ 9•ý°Rî²ßGA%Ÿo=tgQ©£É“=›–«XŸ€‹Mä+]B‘g׊¢¦šÎ)Güdñá+¥úHš›]è#)î04>ÂÛS¾ìÀ$ÌFä…WÉÂOaÔ×?´ìS2~×¢OJífCƒ>[ÚÔd 9Qyi)>W£6In¡–£‰…Ô€ðê_Œ;¿:Ž†ÏƒdR ‹X€69Îîã ìÍ7„K)üF7óZ4 Óî.Žq£)E%J͘5aq{«íNœñÙè.C¦î±ô}–Îs»z€ÍãH=‘ðAM1áYÖèÀêt=L1þ|<À„-]`˜’‹N8ûìgh![œ¶î¶ú ¹Öù§¶³Si¼Ú/‚mgÐ回Sšb–FøŠGX*ãZ"ËUž-Ò'û)á­ä·l!A`…{ô9çv‚×íœä…T„&Šì‹¯­p’­87<Ð5 ÑÉN!b Š˜³ò|D®C!1M¼ %oEÎ×I)ÃýäÕBbFóâÈ' tâ£Úé /ú±ðôN¯¶¿/å#‚,-î0{·«æ'Böb«8=É6š~šZ=)Ó¶‡uTÆA‰ìA-­¼Çl©‚/ßðÅ7?U¿O4ƒIj…ê6*Í÷÷¥ÍéöM¤ÉÉöMH f$UQˆê¾Àr¿`6I’D©nêkmpôIê€WÈ.«.þã\Ó™¸Ü|™R~q$8T×4prh š|÷€—EîdšÿÆ]-^BÙð½¤ìGÜP!¥YÓ-§È‹Ì0Ã|ñàTšUh^*¤~yí·  áÚ阷¬ ò¼ˆKž®ðÂÆ=NûPè]í0d–bü³¥rƯ u)t®m7õ8;þÑ:˜«-°èŤå#ˆíU`©‘i$‘%ÒÕÛRªú§Èìì1·ëÔªõ´x(ÆX®ü ‹üç­íØRÇD8!¯ñ*,3"åÑûö¨ƒjl´ ðT8rz÷ ~SÝA+Ñn´¿Ó3Z†Ãå%îº5­üæïÈ¢÷¹Xœ@-˜;á¶±3£wëçÐ.î¨â¾a³&Ð:‰@,™Ì%m“¯nQGR»¨cx­r—‘C>»f Ò2‘ F!ÑÔiœD'‰ŸÜ¼D×£tÖìŽÀU$åÐnBǶ­Õ‘^»Qcçÿ…F¯*ª ø*ùÿÖ@$Á¬[³¶šËm†qßy«Ú!ºd’‚ë¦Õk¶i7úÉsžÄ›1W’¿Ø;;Tÿ¿ {Ìãõv÷«;ÒIÿõ:ýÏß-t0&7)Ågç6â&ËV\- ½_Kï_¬]ûa!ìW<]ãÑY$ûÎ Î7ZMÕÖ'u\wòÖÞóòx¡Ûº¿ë®oñù®MM±²íi¢?h°ÄÓ&’èw‚PÑ SÄîö±»"¾=Ü‚æTGkÑ{!’gžrƒðÁ°{ àÐ(B`¡¹k¤ cÈ’õ­]òw`@{¥p废U8ÃlÓ-^ÌnÀOäÛâKuQNoö¨P7žÈÒ=á̹®«É}]==¼jœ¬‰v•%ÅÎÂ[Ìܱ¡Œ]±š¤×^U åÕ.4iù*ê{ÛÃÑëÁ<žW•¢¶¼^ñH¬ÿ åð¼¶âxë ╎(W,ŠçµÞT"¯"ïÿR¯]Fomñ<ìaoOWÀà²¢ØÆ8gªêW¦¼5X…‘$jmªü(‰Ú™Õ´iÙd{tÙcŠ% ´ÝœwìG1±Jꢗpš;þß­pòbR;”$aþ¨P+Ùª”L€â–Þqµä²ÉŲôë+厱?§]ld T P×SÉ ÇI—uq4®±²ZH P«—PUeUK9.S¶¦íôBKpR~Õ$e[I6Óv\ôÀÔ)P]Ó!´\ìjp$ü½Ý'lB¸ÛQ¶RÕpU”'"÷è§DW™1)¤^fëô¢GQnÈÆ²W+œ'–WáÒ}…4®@]ÑTq!‚BœN„_4Yiýì¯*µ+ЇÝYhì „l2@ëb Û[#÷…ThvRfÊÀ"§¶ µÙ‡\èHzIÁ+ÅteZËjøÝ4€…¶Âz¨ÛÍ*Îÿ¤r놶™\>E¸ s$e9æ.$Ž*Óø¿«„4`‚€,0÷µ þ‚«™þ÷ÚSðµ¼®bšn:?®WD8œ?džÈ0ßq¤Zÿ`lÑúºÎ›O¶h|tŽzË£-ôR8ë­Î6èâÝ^|†Ã™F{0ä.fßÅ<ã»áÀl°=4Øø4» ›xâ¶E³)M–rÅ8*vÀ×-×Bw;’ˆ/Ånh¢] ×.v;ÙŠ`[Tº$ìvÉ–ÍNXŽJßîv$(Ñgˉ{Îñ¨²ž(òâù J·¾x×]‰û¾®5à ÌpÛ1 “Æ‘Ë, ;Ÿá‹QûÓp“¾>ŸÅÑ 3Ÿ1Á?á˰Ö,p —QQ†›‡U,H‘zL ö­¤ 4<«bP7Ë%W'*hê¸8žªÜ„þ~Ƈ±æ>Ÿá±‘**Ho2« &“6§Ý‰bt…ÙW;ÜTÌ0æ©tÚ:”šKÑÕA‹äÕ tˆ®Â_h’~âeÏñ>h+¿x¤ÆÐ;‘Ä®K‰7~Ø¿¤ò8'·UbTÅXÀŸÇ#§—év!EŠà%2RMÛŒ+"8¡šS’œNä–ç¶+Æß+,/æúJÐå UDðsêóþñÎIr<˜ð;”NÏÈ:Þbn–‘‰¹Ñ¿ ¢œ¤è…±ûµ .ç Iš0G´âöP*?;PÒW¸¢ü‰ó*d`â°LžŽB=2§ -†»Úѽºå2‡)LD*Q²gÚz!£ÇUåºCxácƒºÇÞm©ºànÑ,y¢¦b‚ÌOL¥_®pºñúýÛD© Y1"£òÇÀ" ÷unñ³•F•ì+*ŒoÚú"WCäJž›´Eö8Z-ä^WEd)p8 \ˆÒÿ”ø‡ª¬.ôˆ­½%ÏXTÕ9uù b4c\:-m>^Ì%ó)r9dzò‰ è |VXÁ F(Š!x–s‹<4áÓZ|¾†W·Ÿœ›’i#ñ(ù•Sll>Ìp—Îô€tÀ®<¢H®ä9œ=ðñžøPA°ž :é)¤œ})î¨æŠNjápX ùÉv )× n(I½¨þE£Ù£_ï¦jBå ˆ<»*%FjŸT Êxœb•#¬ ¹ºb˜oEÅö|y¬ô6s9!ò¥$cV‘ÒÚ¯ÕB¼Ž[¡‡®-±_•ªb,è­ðUpNHWà+{/´²˜‡Œ†SÊáaÈå¸3ì·{˜“n¥D«U·Að,]¯½½hƒ&Õ׃Mû¸5 R BC7ùœ§}$YÌËßa/¾»9`OgË0…­Úõµ~”¼«´SŒè£ D²… «‹r9·Á<´Q˜'ù±ê×#¼érJ©”]fÍp"t5O+oQô»ƒ³”`uQ.0XÒ‹kAóåÌý8¯•4‹þ>¦¤Lý ‚ÂØŸ¾¥-÷¶L»|,ƒßa'®…!(àe·«°hU+L`‰ÜíÞ çÁã—ækÖ]Rwï«<·ðÚ³À5Huz]°Yû¨I‡TF齯öÿQaå;DÀŒh¢³Qo!¤ùÌš³áÐæÐcdDöÅQ^q@‚Ê2aÀæÂU¼9S,;3±Mw*¹€[K ŽŸªÄ6ý9µÕÄaŒž‚w6Â¥> k»ÜsB>Ëiuc$7{>ÚßAßLX yKp²ÏÚ÷ĵc–2’ϸ»–å`<ýø ¼.Òø­4îz­vš;(0A,­¦ËíÊ«ZñÓ¹”Š© ?"§†eS«–R£ F'+®£Z“|a@Ž€%ÓüðÔAǫ̈QÌ¢ªË‡e“Yé4›qúw¹’GÀêr°ї¶°K€}ùYKÈLY8ˆR²9Q ‚ã£êçže%×{Ä=ô“0Ö7ƒÛ’ÁÏîUaû„¤&ÁT1]j–øå«üïËU…²tÚ,[×`aZ´MÂã©Bwé« ÝÔâD•Ü\ÑEYLeZÐÁ±ÅÀX])]í™oU}9!$®ˆíGCÍÀ3a÷‰Öè¯ÃqT}<*QeX™VwpÃP_±³Óˆª‘ ©á%1½ÇBº5¦›šfrG.Yuú‡b»¸­“6ˆ»Ç4‰ô89ºGß ›L™‡\Ü­ãÇðœp%¿¡ƒÿÒÜJˆªlÿ*£ZqwzшJ¢¢´ªLMös©%ú5½·´i.®¥´9Þ:c #‡‡ Úæîd â ½ó#z-G9¬r§ Õ&ýŒÊV,0³q)®$ÆšÁ²Õ6²×VSñ9àú¡À”8h3ŒLÅ.P˜BQ¼øŽÛòç%úK[[Å‘Tâ"@ƒSõH,‰‘0ÍÆ¦¸X‰*)nT®†wÎÒ⫇c—©Æ¬Õð~ø©Ýó˜b§‡#À!ýQ÷¢ò"¢ml*o°i:©Ú È̯‰è úp⚺ýÁDZa ™da/®ÚöK?D62c3§Y+Ý&u'Ó@R”¢uEòàqZ©ø ×S5¹S’i¨/î…Ÿ¹r ÊclÓ¦}˜V½ 0ogãÞêK2,À°gcׯÀ›0´h¶sŠï“I¤²RÜLWŽSÑJz¡Øa¬Íe|b ·E -8BÖ+¢úò)ÁÀu´r¯óaàð¢_«Eï%â&n OKV7/ÍÞ«É#‰´*kˆá”E×LÄv½&kV·éLÝ8ц! a ¡@±o ü™ Ì£ðçxj±Ï­å$ÂlaÎõ«õhüH ·ëéŠÃQ2(¡´TµÙ ¹âµY²…iàb²¥åÁ([g²qO¢{+A¯ø¥Ü(bF~2K·b䚊ÞÜ5K-[-˘cþ-ø¨%ß±YMë 8=åÁ?Ÿ!;†l8²ÈìösC]3hº²+îPUDF´’ë'êù°Ðy u_P;ÊZ&sЬ¬Y|®–gMb¾°«›ÅÄáTiÎ…dµQ¤„\ —ÓáÅÅØö´<Ä)¶ÊÞc7‚]®-UðËh—J Ð2~ïIêS7|M³â`lò´å¼tf7¤v´ºc_Ý`µ'. XQÞ@QrÆæ ’o*iS'u£"¶K‘“æÔÍ–%`mÁÒ¯QÙj$utÁý‰*@EØ“•M**ÖÂ}ì%%}¨v؇±ý\ ѵ{½+ Bƒ^û°Ó~ßëX´øW~ÎÎ\—±$ŽÙaçØ^‡ž§Ë)fÏaœ!è¢aiÐÊ¥#’/v@è)[õ‡ 0ϯ sXœ[HEG×E“¹ÉWAÄšÌè–Âpø8iœÛê ë¢YëÌMéM—ßðÚj`E‡2IL–,S= &Zd+z¯ö¢èô„wu>‚öûQ3*{1>£)Ó-ñ+´ðs6Bù¸:…w…~ám kFÅž“*ÉÞl0—l,Cw¥vš*ÆH5Ôt‰ÐëÌqZ¶¼ÔåcÄ%ca.ÇÈŽHõÛrºâ¢ç,ç`2#‰ùWìäê*-È9k:«¦jV²g‚C¡ØÎ’ƒkÎã|òR(>ÂÔÒ˜‚ Á±N˜¶àÖóŸnMûâ(ó GTE¥«Û»ÄAóbºD‘·Á¸dªœ²$£`kìžÒ=âä¯RÙ¿ÇÍGìF¸gggkPüµIïKHfõ%óróÝ e>Q.„$Ô-—+P)Å)º!œêÂÀ±Êfé ‹QVÊJ«ª€¨c+e¸˜—J«9‘²l9½›¢ë—vRí+J¥ñ¿ªS`ö-UµNIM‡3Ù“âþWáîÑ pÑ^Ô>¦4j÷ùŽ?ûÑñðâ\¦»·æÅHfü…ÓÝLP;½W[ÏÉUrÞ%"¹iQ3$I(ðºŽ/HÔ™1àJ.>‚CM5|®I«N¬‹”RÀT:€t¶®üG]-XÀ4ëªì”žF’gäÍÅÂäÝ"%¿W]ÊÀ°_ÊÅŒì³8öò‘.ž8 Ó-Ióßi¦¹.J3± N¦±¦Ð°¢‚‘ð:™p.FY:VB63€° Œ«mC…¡Ç® ûû騀+ ¸EVÚy#ÈÊè” ´¼+}y?´ÐÀè-ßœà‹Ét[¾«NúÖ;:MŽn£Ã‹óA¯3î}\£! ÈšbÍ™ÌóòÆV0Áé¶EÛãïó*ý-›kó"Èaöä€ïa™5+mÒg×öl^OÚ§daÖxU|™`CÁ'<ŒGã‹AaÊÁ‘4ð‚ Ž÷[V©88¬úi[ö{Šy]t¿%sÙ/› Lÿû¦ Ý™$ÛhOn¾érý„DøøBPa!f!ë µöÎÃNéûZ^«ÛAiX¬¸äì#XXZ!¸3Z¢"F°^V]äXïKJ"¶Ÿ`A+?~HïC3t …k -8ØrÄÈ\õܾ°€”–£lLQxé›Þíõ~lu×µ$³Í]ß“ËNÙo¢ôdBR…M³ÒÙï’Q²X´³\#íiÖë|b¾Ÿ·L_Ü¢"xîk¨râ4]Á.ô}³³ô1ÏY©&ÊÏp/©?=e¥ Ö.Hc vå dÜák±“½¤l΄t©BŠH]`ĽD­Dœ%féçÜPj³•M aÝ6³jr²²¸m2.ëŠr;l©õ6%‚\Î"Wþ%w<®bo;xá¥àô]Û¡yñ ‘¹Ýe¡4e6ãZ-ÞÛ§cèsÅ“Ùô&õø$˜ï“^š5Æà¼Ûo—rK‹3ЪÅ´öö÷Ëè¬&´šk·OƒR%JB ë…×T“eÎE‡ë;œ%)o°1ÖIQU éƒ:ò`%`àÅepI4y…/%•›Îaë¦1r`©:`ÿì8t7=/k…¬#Ëì…úǹRg\<;/Œª¦BéÆUˆ{Ò¼m¡#ŠëHýt°«…bß ^JUÌmPâLça3´Òè:b_I;G KZhár(Ú¨TèÇð¶N¾B}èkKv#¿K®;áéUø·äÄ$Ë#ËËPjA%2ÐQöLíxÛ‘?^sñ%¨±„Vs*Ýãu¦G³ÂíØÍŠ‚ƒy­gÓ|¥ܨ( Ð(ÿ‰*Ü)û ºÑN‰´‚ š êãîçÙýb>½!sUî;ºâ„ûÕ½=­'9‰ÇY$¾»¢³$é`oª|¢üfÈ{Èq?.:¢³ax/Ó(Þœ[¨’M”KÖ-—èJZ©uÝîq¥h1jâ?BvzñZS@ŠéUsŽÀnä0lMq&mÐÛ/p€fßÞ8GuÑ;2§E‡%6Fí£X>šBGåçé±Eþ5ŽÙBð,%›>½»âúXW©)”®¸g±¨¥'l^Yqeõäe›)6C/ýÖ[ŸBhxÜ‚†ŸõC¡XcöGcÒXÁYã‚ÂÚ¸ºf¹¬Ìx?ÖŒÖpFvüÑØë eÂUÍåµqõôOËÇ¡À©`N~Ý¢µU•«¢’Úƒ—úñ±¤|^¬BÍ´Öä±µf$²ÐÆMh:ƒ÷Ãj1©|L[êñÆGÐ ³*^×ÇuÕýš”ljŠñ(w©,ïÁÝüµ;þÚ[|¯k‹ù›­ü³½ ö›ÁÁ'äåÎ1~î’1ïfELGù\T´C͸ J~¼ïì¦.Ìo¾1±‹3z•pÈ0°b® %>Ô/XÃã-VýBâ(©׬ý­·öaaíÃÙµ¿sà¯ßýî»g*—éGÙyP'+þ¹ˆËÊËhᕤÖ5w¦QwæÜ+™ó¦ KÊŽjqæk†vÉÐ`äßV‰›Ã•n@×}ïWÙæ-+}ÝQû®“Îkë4Y–u âò%í;(´‘š­åcB. Êô=¯ÙYvÉ´çHë¤Fc¬#¾ ‚¹õ ¥+¿ÏÔìžql”ß'¥;CÉ_=3±Æ“§o´}>i£ñEttÿ^ôÇÝþÇN4>é¥ãð®RQ°Æ»#U°~ÎHŒûØü¸;MŸ)~€þò.w;ÑÉ­|™M~±ÖÎàdóö’nÅj5Ë(÷G:ªÚ9¹³[(JÃoð£v×.G‹âÕJBI\S9ž³€äŒƒ.&Ÿ©F*2˜†™Òqèä~Æa­ö]AúñC/+J¬Gk.™q«±–•$¸ü&ÁÏ4wÊsC•-ÙU0¯Í<ûÆ>> ,g”ÛþÎÕ\[ïÑ ]ÁÈhUÕ…}S¬ ˆîá$,q¸;·v|zCÜÇdŠ…ñUÚúXÝ‹®þBÊ©l’:Ím/(àdQdz–^8‡ÂÌ®F˜Ãb(éoŽ];EySSŠ#ç±ùñ‹¦V’'¬åžÞbͳd¢u—I:YåB¦ÜÔ˜ûTš4ôœjÞ´R]¾¨ÊžOOܯU†I;²0„Xy‰H3ý’bO†TQŒY´ò ËoÊÁXí(>¥£m@…^޲`/‡Ø•Ó“tñ%U÷ɪA‚ñ¢ìiÆéœP?ñu1ØÆaÙM,5¹BGnåƒe{çØ¾.†wîlè~µª¶[6šjD<‘™É ‚ôted£nBÕ%¬Y 4»»…Q“ï€rªfÿžÄ†øÏ÷·Œ xÞOÉjÃ(Dúp«]˜-¤ªO|·¯³§…2ˆò¥Öü±°²º(ÃÊy2zy¢0q|‰ÌØ*nŠT[•–#bSWÖ” “¥hÁM­ýÖmç Œ¦ã‡Ô¦‘âõylFvf’™=Ÿ&ú°rzºXEËïa5GF3Ó%–t[Ü `MlTôŠÙgrr'VÅJX„J?:wvEcÄ ðýZ+ÂñE¯wñ¹Ûÿµ-"²-Ø»·:¬O¹ Å‘¦]Íî(Ü¥¡›ìˆ)ìÎ7rêviƒöâìÑ,ØD†¬ÅiÝM¨Ž_QÈ]è`-€HC¬óB'†iA'Op—rKà›¥5«—-ƒõPwÅ”ðj&®¾"°³ Õ»·ÈåÝŒ¢Z'Ä¥à tÃDÇ‹ÅC-X>SY,r sâ5¤Ub*ˆÑxІzp]w®%’r5R* 7ˆ¢_S©ƒD5žY;(9ªXG>Y̳Âi4Ÿ Ôk4“E8. (Z— 7 õ¡ƒpÈ‚ƒ!sämB<ˆ%ד¿ØJ46„ºôU,ªÊzÁp(“_IU ­&P¸€ÔE\•‹Cè$Á¦ ý}ˆ«ïxHp×xAQ&–ýKeÜÆ”ÈÂ(ßւ﫹&º ×»4a‘,T‹:†²”ßôb.ºG'ŠøuO²§hû++]=_+ë,x^%×I¦êÿ,tÙžÛbŽžŽ–ºêÆ×ײc–.-›©ñÏÓ6Ë jÓ¥ž±²\æ¾rÍV &6—Q©)0JÂ[žÍnƒ[ae"¥à›\¨\®³ô÷ðRüÝØât‚TÌÛòýØ®BæTA#?7É0§ÂùÃ{å»¶q€BèÈ$‹´ÁàìÖm‘uu¹“œT†zD`Á ‹¥xÙ¢?NÀ·™fê†éFW[…VÝeªÔØëI ÂMX4iÍHki±ÌÁSÎ9aÆD'’0QIJ«¨‡R45Gq–£)Ý/¾¢\/î : í¦ÂU^…©êÙxRÄܯ½öpÒ*ÕiؤÚöd‘q„@öû4 ï\"yœOÿþÀ¸ïbÛ[YÒ,dåW-&8ÏJœè¯ŸLœ?ï~–Ÿ³a¿R¼»ÐHù zή¼²Š¢‹€WDP½Ô©i±ìK®ø®Õ“›òs;¾õ}ßÈoyß³NêÏ<ìà{îæDÛ^â,/x¾kWì./¸Ï]1ËK·,ÉÃTÑÌUÖ™Àǰ NÑ««rmÒ능£”¥ÝS±ˆË'Ò‡9¨¤oéÜlÅM…Æ´£æ§ ©}A¯ü¹>O»¿àÑù)©­¹´»xÅ`ž¢»¦4 ‹-j4I6ÁdßÎUÞ¡œñZXåeЪ,‡*fGLÅM4õ(z Ê<;$£ïâ@Ùç´¿”ýǃÛLÈÍKíÀ” @A¤µ¨b›ºˆJp‘vÀD)‰l ÛÖìRåVV¶ûÛ!×B„Î-E«){)›Ö°Ò–éËtFãäšIXfœjñ:[•ˆs&J]¶ÓJöíÕ 50]{MBº”ÍLðfSÖóM²|Š´y-i]1Ý<¬PµÖÉ7{‰°u>‡™Õ-%é@ÅÐ4Hº­±avÃÆ¡ÐŠØ‹·‘‹/_íoÅôþVH@¬l€ãd¢šå"\DŽýÌ»•)’LÍô ÊÚ¬Dâ÷Hå__>ÎË£=øj§Æ]ÿÖ/ì –?ìw†þ!4¤Ï½ZÒÎ [ýÏbXº ÈÅ©yI ~Åï-#ñ«öì.»^¦Óµ‚ƒÄˆðeÝ‘‹Z´£C"Q°ÞÇÁÿ™ƒM̘¡nDof¥òA5Žú‹åêËÞÉb6ÐIÝCçËI œ¼{ §õ¬àëæÞë·Ôƒ ÎjQ§½‡ù¥ó‡€u¦÷×ÙL‚t½…öu..½먻Løö>‘±lÀgNj{ö ÛÐQ·*Ž:³<û:ÅÍègߢ«Åò7šý;šò>LyP‹ú8eÌDB~þ0ãZt2OîÓeþö ® pÖ°[\ì÷œ¥²s–£Ô¸Õ°Í·ÑÅQGŽF?­Emñðf_2$Ó7œ„Oƒíª“ý$ªà䪼·õ½wÉ|àN4.Î2°·‰f ¨FY+Ìdovct÷FpÙ†íÕËuÛç¸F²-¨›ÛÄ5¼;5$¯ßq{Ë0Òüžuj¦& p¿ˆ7ö¡ñÆ&Ów/€ƒæÿVÏÿ]ÐbÒ¨©»Ë ‰F:uTÜ32>&•I¢žË¯)ñbmUä!RtÄÎ Åðð¤sÆò#PÏÙ1Ðò‰Ó^PºtÌÇYäÈÁ [R§—^—- ·)r‘“GGuµ¿ÅüS£šLßSˆ¹I&~¿ÈW:[JIx£­1Òú3ñ)8Ы&WWƒþgÉ6š;,3)òA9pBèAf¯{Ù®G>Mg4à÷Köy\B:¦E!A‰´9ìÆÃWô§n%Q¾DšI’²t}J8…Ù LWD© ìGV(<Øí¼Š;å’[óÙå–NZ2ðèŽÇÃI—ìÆrÁ»Cd>W P´ˆ+?÷‡çæ€pŒ 9À踙ó—>’óöá‰JþÏ}<¹˜ ‰ÚŒF‘f—áðóÑ«ËQg|Lÿ~ì¿ê^ŽÚŸ˜™{Ho~CìJ©æÍŸK0Ÿ x";²=íÕ3YN¿*/±Æf.8‘zÁшym£&ëªÛD^m@EV.Ø©´BV¡a+ú8W~  ¨”Q|þÛ©§¬u«ÒÜ/&ìå°Xs\ap%j <—^·?:rî‚u·ÒÙÝØù/÷ϺeÁ5€é§0ÐK}í “ºzê!±57áÝîEk@ƒòè–¹³ÛkOÝ‘Ÿ·ÇG¨ê̳{L×£J`å(r`ÅxéÁzö´¿6F½OGÙàT³¡[š8Þȳº‘"®™LìáY{ÇØ5_éл”g/t)ƒû½åÌ­<{é[X4ÞʳŸ+CÛÝ9:Ût+Ëöê»/fðØÏžu¿ºsJÑ@øîqW¸eÕ;wMqánmw·“ ºÎÕ¤Ó¨0Iú}hEšµÇŸ"«øc=) „ƒeD¿ùÅp|¥ÀÅzeè"|Z±rƒ§™Üü¤óסÕü¯C¿„ßmt‚áÃóëlygªÒpÓÞ(Îs–¥ùJX‘ÜÑX­‘N>tŽÛ1þõðÏ{þô~Ô#¾nÜ }xfxq‰Ïøê—NóêïT¸”3êp,¬ªª¿«¿\Á`‡ôçèb ÿÂÍC…ñäšÀ{ز›¨Ç½‹hUÞ÷Ú#ÇÛÍ*_£|¡g,™/y èWü¤¹úeö«acÙ®lh,\f,Ì[,Œ`,{,\eÌ,slI#±0n"ýtúGÑ`xÑ»øð±#ƒ’ý’çÜ=ôº‡Ý1€ÐGÌ>;v»˜}µÒÞ;‰/öþV•¡}÷ãè¢ß‰£^ûœTb {\×ûÜöåY;üN5Ö.õ…ŸÙ¼^ü}j{ÃÏÕ˜î{Ýϧ$/¬ä‡-þ. bU~Xþýð¤=lb€ÈùèÃÎÛº|­³”GT}–J’p%tKc.VþžÅ̺ðŸ3­eÎ16€6hò5½Û0öy‡®ôÎ{­¶íüc«ÆWƒNë ŽøÉÜñîçs~äòbxÔÚ‡w§p‡­&¼œ´GÖkxwÖzƒÿ^ôŽZoc«uÔzãŸ1 Tçw-4ãôúÃN -"½þ)¼Á~Áo¡:»‡Q¢­¤éôÇÛJp¤~÷s+yCÀ›·ø¦ßm%4J¯ÛjÐ ƒQ«‘8íG­-± o5p¼óöe¯ÕÀÏέF“ú„/[ §×ÿ _¾±;Á±á;³wqˆoqÔÞ!~»ãžŒõ[û¼]ý߰ÛÃw§­ý}þõ¤µC÷FÇÇ­}|ÜiíãØÝáqöWÙ… Ù:HªkŽwX~¼ä$NÇwB Ã7t†ã>sïð”Îñðîµ=W ¿§3µp½Ã‹0#\.Vdá£ýuØç³ò[g±ÁáEŸ&Ñã“í ºt²puxð¢Þûθííô‡öùy›·j0ê¶öqà¬vëë­&¶ò·š¸¬£NzyMÅû"böï(¦€WøÓ¿è÷;àïáà¤ËÞ€™(6 î]çðã˜S_Ûã\Þq@TÇRJ¯ZëwjõjôbÅ’zÝ„“½€²—Æ"ÌõlqóJºÙïÙ epS>Æš£B…&!Ö~š+“²@k€È¨ºR8~ǵœºL☢I ‚;fÂ|Èæ@®w8q»",>'ÍÛËLÕ¯ ` ¢%ºA’ÿ¸ø´Me…°-È.ce”nT¹ªk6„³CQFVMܶZ5lp>ˆ¾,fJe%Q ÒÌVÀNb#ЭÌHƒÇ‚BH(~÷‹&È÷ñò 'Í@O§øËëm;¢§nN¼ùð$IUÌ©a¢Û—k’„¯ ÍÄYGÙÍ’gO·ôdÝ£4{ƒ x1NGüßyù7.)ÞÙž.Fàq}1öƒtà=¦2PÕnŒ39– AÆAS WêK/”|H•ûÅT<ì¼ëªÅ¼‚åÆÙ¯0â>šTÍ-À-hx—5æ/©«–†B’ì+ õõÚðª¥é+H„èæYžQ‡Â3’B&Ž²ÕŠŒ‰Î9­äùG³Tx‘L‹´¦}) à.FÊT]TËáÝ8ª ™ßy™íÎNÃÿiøoozÞßÁ°Ì]àqØÝýê2ûÜÞi¦mÚƒ:ODæfãb«-w\—š…žOÜç-V6ÔÜ¢‡=–ðଯ€t ”ëaË1nëÅÖ ­ß··Uiì˜ávMÛÝ„¶ñG·¯éÿ|þ$«VÉ…‡QkÒBÙæµ <²=$À߯õøÌ#=øþ1׃ ¸Â5“ŒhT;<–*àÎõb¬ÕŠê<à‡]¹Û6'ÍORñº×˜¿S]â0 ï„õ½VwÚÁ*åÕ49OÕÀŒôÏ]ÿwÂìuw8Øz%‰ñÓžÅïU-€Mtã]Õ¬ºCS„Ióf}8#”V¹Û,9е‡ÀK2lK´J!ðÚÈÔj|þËgèŠîV¹{ɧ2ÓÖ|QF®¶hÞ÷Cþ~è?8¢ïõâÔ1 RYêÐŽöhËv-Loøqõ¨PLýÀú½«~ïšß›Þººä¨D,$%Ÿ›®ž\Ö‘wV±c8]àæw) ƒ‹ªº‡]N8Ä^²Û­Ú °ÃCÄ¿ì5„\â8ÑÈ4€=<U—¯êño0/èJ«Èeìæ‰]Ž­â—[¯]óÄF¯bkEÕ¸;ìŒ]ž ¿Ñ0¥VðfítZí½‡<ŒÓ=ê\r1ê%GàË0ò}â-á(¼Ý}hÍ’C;²í(xdðë│N}±g±œ¡VˆÐð!kÍg¬¨áÈ“r¢`¾E/J¬k6×P5\·ºBhcM‘ß™Ÿ©•+nî×½9 ÙÄé“0É›2å>ŽEyKñ“§œ£lxbÑ w/ºÆFgΣ ’ê€uîó"B«­ºŒ:ÅïN‹ßuÆÇÅçûÅ/ûÝâw½ÀwƒQ¨Ã^`†ãâtȤVm)õ­ú«¨¡ty?Ýcå—O•Ü?ËãË ±,•¤Ê@*¥ít:d?©‡òæÖ­UѼ@æŽo*ïÆ‹šn’º#ø¹0Ÿ šÈEJŒ½Aéß‹ÏÃÙKªFÕno|£rÅåÄë·EB¿È«SÚÅ !ö= =.Ù*Œ QÛeΕüGoÓ•ª×déäG¨:ý‹”a$ž,BSc4wv\Êçîø$j÷ð¡=î~êüEÚaÿ‡ ô¼‹õ$®›ÿáåç«%c~j÷>v¢J« (ô☣]Gý‹¨= /à^ÀJG|#6`¤$Æ–ÛÚ>¤—ŸÛ£hÜ>ëôkÑðcßZpép ·'ëÈ.I_»ðb¸²ÚlŠzŠÙLŠ $¯1*æI¿ŠnŒ‰| ‰´ŠÊæ¡ä1vÈeC`û¤4W—ÜèG´1_*¿è•nÔÃ:ýô«ENÈo1ÏxÙ!b¸Ú¢,ò3àúºaó«úÎ}óû¤*æ§žû“–fúèÓ#Ò“Mš 6äñ¿¹ö|¬« 'ªÓ¶|Ûv¾V©A\SÒ’š%¨9ýv«ëv†ó枘›3úì¶÷mU¯, 6ï}ž¢þÚ}°]úà›_eæe4tÒ¸®"ùMýmØ#Eù£X…<òìŽlüêêjQâÅè¬1Ô¹ ržs ¼lH6Òâž’žzÔ¸%> A5›’úœ'ѽ×Áïéwçk*g ?:_~¢/? cÙ¦zÈmÊâ<þè|=Dà§wYæß±LðÇ!нÀ#éo/éÛÄýöó9}{é|k&h@’Ïñàô\YÌ×;®Œ²•ó€®ÒbZÄs”±*ìVMãsVèø^ØVZ%•ËF|ÉcäËаBþ!/Š{÷CìÔ¸ßÒ§ÂL¬}œ52yøÌÉ#)æM²û46÷„eWrÛ$ÙUPPL¹Ì¨ÚýU,rÉç1|ï¹à½ÝžÜ=©½õl·3t¬Ÿ¡/ó&û뮂¯Cد7Eå+€Ÿé%c~ïv÷(eª³µ|J_Æõꎞ}S&CjP°CŒp+O€™1ûö‘\Û`,vq­h•¹òþÄŸq.ü üˆ} * ñèÿ‚Ú®Jûý¨;F°b®ã·÷ŠùzàV‘t©ÇAýbPZ¶8)Ùb`Á£õÆ=½:tÍ3‹ÛÙ©½~ýúÍ‘F=]­eQâ–ë-J¾6|Bä)ÈzŽSႨ$ɉlŸ7S¬æ™Îb»ìŒ¤^(7†jûŒÁ6Àý}½¾ãÞE{ÜwÌ3juÒãðw\áÇ|¸P$µ£ú+»™Ç§¨³Õ9—m½;QåôlŽÅ×ÍÌÇGÝ’KÑ^46×°Â?5G`4WñÀWaÔc–=§ª†:ìzÀZü¶`,¶•'uK¯á10fz;ðX€ÁH<–Ÿ¢¡Ü§,ËÌ QÿeŸ9“ « Ç¦B,(qˆ •åäJÒˆ#;1ÎWü×¹ÊWD6îmzshÕ0K´ïÐŽËWƒþÅI-;ij¶ ŠFb$‹‹—¦ÂÙ5xN`d$üÈØ3u?ôaÓbÜç=«@{òßèÞÏÀ;™¸ï3 &¤lºFÔ‡+Ú'÷}Üo ǽo÷ðD æöª\±ù™’&{·áÄ÷ƒÃä%¹¤ú&p4¥%inûÎÜ s;°æÆ™¯54r‘t"é™u Ùô[ÇîIÑujf1ß´4ÝkÙhˆòK¬¿Ãu8ë 8h¼©(33.JdÁ³ôaAµUë¼Aî(Š;^f’€Ð k“.Ĺkõô©8¾WR\£òÓ\š¥÷:ç¾*† âb¬8)É0¸w4©±åƒkûHGÄöä$-ÄÑ^à«þ;ø|ƃ¤˜*ümAaQŽè’.GX-¸Ž=EPǘ’>‡6%Æ®Ó[£O·$L’ ´/R–®Gò´ØqÈŽBèªs ýâšP;søe¿é‚Œï5 !±wE^ "D4\[r÷ ½"«™ûî^‹1ß*~ÐdeÜǺð bš·Òæ‘£ªå½Ï±+ºB‘+ˆ·hI6K {ÈŠ)"ÝøIXJUµÂ3×H~ÓŸ:ÕPcX©~—¦?ÀrõûÏçVlÏy°fõXè_Ûä>v§†Øæ˜dïšð†^ ø(€)·‡OþóùóÜÿíßÇþ:ö3}ìÊ‹^bO;òLU¯ë†PHúŒo\ŽE _²Ã¡æú¼Lõ’êp§ôÁ‰4è1”8I¼¬è$½*‹ÅUÕäÖUç$3SEä¨<›…¤5©eÄ©¸¼?‡ÀªæhvSW Uå$¥=Ð`'­ý1.Ífdc烒;ªÚè/NˆS²D¶‚GYU³Û=@­ÇyÖÍwudxݳ„û4V¤™ÜS®Âé}›4ÌX©âêŸS›Ð|ãjà³}‘_D›0Ìò€vŠê ¹âIŠÝø¬FXür¼|1‚žY=xXq:¨óaöeÄÍì½·coKMÔ%‚œ\„×C´ÕðÏ( Áœ#O° ®ü‡ešÂÆ:E\tU®ÿ¸ b×q­Ü<ƒ‘¼¶SºZÁ¨[m¾ÛMª­éOÜ~0²Ú¸º¡Ž}ÙQ“ƾ‡_IgÇ}ü®å˜®áêl†Ëp0Öc{|ÍòÔÍÛ$ÐpxYO1XÜ…q]~JJùxœ0’èütòSWפðOáýÑúáq‰©ª¥˜!CÊšV3.8ý ÆIulêCét¶Àù/¶Ú_B¦ Ö ·œóÓ7´jí¸ "J͘6ÔUÐ2ïIË'5ÊñÊ݃‚›bðòû>‡Â0Þp`¼ÿ¯äÞïNP,îY×èvRIEUêþIއõAJÿ€Nê^Œ”>ðñ êËÉmÚ"¦FZ{„}‘”CjÚ4¿h9õUÆFçE_­ÖpP0‰ZARª2¢ÿˆ8 #ö÷d@Ž0qgF¦d)•€ƒmƒ †›€@Œ«5J-ìÈ=íýíV”Á<{Ú«‚%ÇÌžŸs6¶ð°6ûøKõ•ßµP¤¬}w¡É– u ø§žNò{ÏCàe§õßœÑ#ĪÖa¿DåMOâcep‹Êê­à»ùƒðýœ4íë˜io¿‚È¢tÇJ4ünÏ%תùœkuð'½Vÿתt;tükÅUr}ØÙH¹2¬MöÈ«€!&©×mÙòhu—)`U]™×eW†äÆß.ò*i˜ûƒÝn·W$FûKhÕß=q€¾4˜E^¨ÜIK.‰‚)ÍüµP\”hæDcéaõ«Lÿ~§m£=™þ)þ(nÁÔ?‡ÃS'ò®gmr­1®ÑóÔnøï®fÅß±x8 ŠÄ‚Ñ= žçSÿ9]Ω¬ç`ádm0IZ-H„æÑYNöyÙGÍ×ð_=‰£º÷ò¶w{=þ€1T¸—I-jc%›;4ô×ȉe^çÍñ±ÆwL¤õˆù¤}=ºµc}ìŽ5~pÇúÚÁ®­¥*¼P="ܳgODvlh9Â7ì±ýܰÞ»õ=1Ö+³Ôh:)†/c}÷r×J¸Ÿu M^Î Z†çÓ¯²‡…Lˆ{&•¡ve°³ÑxÖL\WÜfò\qÇT„n#·¢ÈkI*Ùt³Ã;. n­~ÈÒWb T͆Ñ4žsż'7”„ šKmY4üÃ?N(\ÓN.©8“ÖpÇ8¡W[ÿØ.þÈüŒ“þœ0Œ"'Ö8(¨D* E Û­þ‚ÚÃvõ°]GVÐ#ÚƒS#­á$•pÞí·ÂNÑý W4ÆIô5¯‘jÛÝ-lyÏ1å)å¢~È3ä©Ú+©@qÓýÅJ\w7úÏÙžsª¹v—Ó¹œÖùÆ=>ØÞqëó˜¹û#È ™‚ƒ®\—ç‚Ó­ c]ã¹óc®;ªõ:·õ %ŽÕaîXý²Æ†[‘š_Í Ɇ;<ÕOQN\ýéÄþ0ªÆèÁÄà¤#ÛÖoÈuV7MY–õÆPöeËŸÈé@i LcVhé¤KŽE?n{J(ý\÷³ÃÚ¿aí;a­àóÔ'bB çOêæªãïöb Õ2ðrñ ¥ âÊשåN§¼ÀLĹÎôGa\伬øÏÞû¢šÙüµYH_ñ,+êþ?»5`$mcÞI¥¯·¸½ÍÒPNâÉkäø—k}¡‚­ùB´Ë%"]F&²Œ0Ž• ì{ 1Þkƒ’Ùì•¥™wöÓቭ ´¿õÒsé=Ý/èÞêvø‡m´0ZzÀÀh¿¸ûUÏ÷°‰Ž ëÎ-J\XUEtíIÍ´{*>î!…^Ûf‘J\ÃAÁ\&²Ï¶<óTÇÊs¬°¿…à¬Àþšo °/­[.ÊÓ"nXY@ðÐõÎZ¨g Øû ðžØnyjlÿ¥¦g®¢¶Äûl‚yOÀøo@üÄ É@çíÏM«ÒѸÀ åŠRE„¢ût’ñ—+Í[½¬¡é]À/ȸµ|Ó#•©ê˜{Û )ßpZš?‚·DõÂã<°‹œËkÏáõV¡Í3ʧãu_lz¿¼æyoÜ=*7U^'õøuþÛ¯Çoêð·ÙŒ_à_øï5ü÷ÿ³êõ¼~ _¼…‡ÞÁßwM”°w£õùbÊ!Ìï¯añÀ‘:ɤ¶/Ii²Ì°v=bÁG/¿&¥m!Ñ8:ü8bõ–qTi 1£&Ú&1qÓ¨,{ÑþÛ—¨þ— ó»6MåFŠ.ú€Dº\Ð7zß9¾vÐhvx‚åËñš—fKÂñ6¤ƒR>%†£”§H îi[2*Ã7Í9[À/¯%{£öd|q<<‰Ú‡°]íÃ+˜ø_?vFëR<½!Ø~“`?L!/LauN[˜Ô­˜Ë µ‘ë6©ñÌœYŸ;pÝþ!œÂ¨s½¿ŠÚÑqûp 3òÊKGÛ‡ÑÖꆛŽãó˜ê”hr/õàUÐÎb>³t¹â"‰T‚œtx¯÷7Îèâ¼uz\ƒöís) !àî?çL@ºH=ÄÔÌËún`ßÏÒgÃ"A8Ψ äC†ïgOwÏñ-•‚ãõÁ†½@(¡»Ûý[ø'ø’+f”žãa&õ¿îȉµ-3 4¸ÐŒt{/ÃΠƒYÎzWü¹݈ ¢ù– Ù„‹qðìêûZbÙ.ô«Ù†­kþ„­k®Ù:gœþE¿w¹=hí}ê ÕÂ*®ÀÖóÌ‹ý}'C$ªñÜ“ÉÜ¢¦K àŽ•!3çChþ„Chnyˆ]/€7Äœ}p'mÂt‡Q­t¤×0ÒëïÙœBYb`t0‰ÿã,¥Ä+¯_ÿÈ|½-dbÙ–6e1<n¾{…EþØkK7éë¹ÃRXlÜ>ÙDò¸QCΛŸ°Io¾ûú^|ìanɱ¾¾å€|Ý›gÞßvotSÍuX·|Èw0ä³/réñH‘¸¨ ÷9Þ„ä'\å7Û^eë@®`óòs)%C ·á>û£+ÐþˆFÜLú L`»‡ûXõã8Üõ«{óÜ#9.9ÀÛï¸ëpÿÛ­qFÉúÇŸ/J1 Ï·ÏÆÇ‘wÓ±ª·á'âÛæó £Ûª[QQJªŠï;ðá|ðq´7öíkoûŸû”¹D`òe"Zi‹Þ½0¤¼ÛR`^(*ãot<¼8§y• ŠÁß(ö~PŠäPõï›ÅãlB~MŠmä ú 0ôn[d¶%&+E÷¨Vx÷Öä—7A›’‹ð¸¨ hŒþqº!f”RhòH¹5Î?g«ì†òcs0):³¡~Äñ^ç2¬&{æ=†“Þé’àT@•Š‚[ÙB¾¤Ù\ÕkZ}›Þp¾$V[ÛKJOä1Ê5[ÞOçéKgÏ|SO ¥Äb“K³~ꌜÂ×§v¯[Š˜šuÊRĤ‘Ú]Í:L£˜f&ä)°]*D7cNÂ*ä-ÆÚŒuÞ¦Ú/<®¯Û†í~9'°ïÓ TNe›a"_8¦»€Yv?€¨ÕïtŽ:\Gyø™'GËCøzõø«rü œû¡ .øÏožP³0¡nÉ„ºÅ u7O¨©&Ô… u·˜ÐëÀÁøzRk rhXééeÜ µÑ¸o¶·½í¸Û±k4îÛù€eØ‘^¯RãEía'ú[gXÊ0¼‰ßn?þ»"ˆµ½%4(Û¿˜š½ïœtñ+LC¹–Ö7âw6#ãY‡Šsê—)þžU€khŽR›–.8 !;µk…ë—7ßÒ+7ØŒ\[©IÞ˜ïïI½µnqïâd;Œ† áµ¢š“x½ZÀ8Ùß~àf³ö•à‡½ àñ±â.°ü±ì¸ó5 kIr°Õv‡¸1èV98oà[a'šE` Â"ç=!)Ý^˜Ù^-êtª “@OUIØÒÛ„u¾™˜JÜO¯ºÍ¡„ËùÇ™Î[g:·šÎ»õW¯k‰…›îÉ»m"hŸ¡ª5›lµ q£îlÆbm± :;l7#eÝ”{JX;n›9¯!c`gN(ßë¸Ñ°ÇçRÃÛÌ „·ÐÍRFaSy ¸RìÁQ鼚oã†Ae‰›j°tJ!TÂó&‰+Ç ùÍK¾ÆÔÖ0xl㦄FG _·?ø ‚ÿ m¸G2Ïu€²AOaÏ#Ä“­ß‰ú6;±=wÖáULFEí ¾ Ÿ+]Ø>ˆ¨£.ˆÅýrãð»¸!HÄÏ-f4'¢s¨PÖÝ Øï}+!ÇÏ- a‰¡œíÞQçDÿ#&‘äí±Uö˜²ì£¢\§Ö|ï'ë‹9gðúÔ^)".ãŬçÀ@´5xÚHß¼q]ß;?›vF®~eÕ¼Óaü-Õì+—Ñ!¼ E´¹æâÝ;ÄZk0Æ»´Æ‚󦼪ԛ Á-çTÃRRmò–€e Î¯õ..kxx‡·*ó¤u&8vXÑèãû!PCqÚ^Àývth—Ýy.G•Ó‹÷1È#1Â=E²qœ Ñßè ³Dǘ€þu-ï-ôæ‚vuø/ÿ.ãˆ}‘#tF–üW1ð¾xÙ‹¯»í“Œ~È;"âwvvÞw>€ˆ>^ô.>ú‘IÒOÃÎ1 €ÞþŽ×Â~$ â†C;˜ €óÑáÅà —']|bŠÀ#ýQåêêüÃ6PcSoÔß"» }t¢ÏÃîp |-¿% äÛ´M­”·:–[È£›f-û†e­`7ÑÏŽ•Hõfâ#¿¤ó;h6ަó›e†}¢ôëdaE¯|!u;çƒäÕ‰ªÆ˜H L¡nãxú;*¬ïP¡„6°"b·?¬F×T]ºªÑ*jŠ;¨nØ9ÈÃî8:ºøø¾×1^&•öÞI|±÷7ÜŠªHD©éÔ~•öpVíó\ƒˆ‹¶€CˆØ3¼µÿ¦ØxXÖx\o5pØÉ¬Õlèh†Kø½÷×TàAiÚ  e´N€­+À£IþZ׸ÑÅ`Œ‡VÏ]Á¨Ë«ÊNû¢?˜°'IïG]üÎ@½¼†uzt˜ðŸKúCËá/¯î葪·0×Óã^ûCÙOJ@¨õÃ" äøO#Ž`ÅH{¤ÀO®Uô7œ’ê«=nÓ3¯o½zIå.)v•rUêÇ)‡]¼‘ÈUãdX!GÓ¿T%g=tòuzƒV¡'•ÿ^%_ÆPæ94½Oçè”à¤Ðç–¤#¦š h¨Ó]I–ÂüñZM‹Ñ ª–)Ñ>Ûp:ÐAš‹#Y6{¢‹<ŸJÓè £O¤> 4ÿš.§˜ÝuÑùÍrz wZ.óÙS¬o-æÆ•Ô‹Ürœ2'S¼¿œO9Ù 1"xµ8îRʛ‡ =„ÎX„¶…"·•’›^Œ³’è>K%Í‹ø\¡Šú:ÃÆSíSÊñé ^œ¼q¶X¨:.Àoðák¶|â@;ð80›†Ì&-æTùgÄŠƒ¦.Lûš ºÔÚóu2KZ³ÓðSx-³Yö5zw4ã[©ê¦SÓšþ¾ž¾å²ªKtR–Jjú}›9ëü9TÇšÎeÈÙ\[’ŠóTPAnFž’χ@AûÇŒ#œ$ Á¸î,z›æêzÀpD¢\Kw‰×üT•‰”¢€E‡—z¹;êŠ*9æ)gêÁ$š6Úwg) vŸÂJϲÁóo në­äöôÞS ­Dsh—n]/`f¸uü=tÔŽ@˜ >œŒ·W2^Ã÷‰Ü‡Sk@hþkIòL‚ºsÚfì$Ò7Ëîà~Ý#šr·ˆx>šœÁ~µúb.Ö´˜òûæÕé# »Wò[°“› ßüaÁ¸.,[¾¸Ž;V ªÁpL¨p- hNE[ ¤Ó{à¿0ø|ödËÜØuöJVbœ5^‘ª(vÒ)ªŠ•£VÎŒ-ˆŸÞZÏ+.w¯9à¼æt½cS”Xn±:8…ùÂÂöËîf‹kX<_gb h館.ìa"kùÜxl QVxE˜t·úüÁP©‡ƒÝNçx¼˜_i]>,"vi‘&ªù¦^jÜÂÅ쵎¾‚¼9dS•¹Ocº‚ó"„8Óün¿q]µâÑ<zTñlÞ½oƒ/a¡0 YB¿BšæÖ0›•¤ïFXŠ‹2cصÓaŸUÔQ´+ŽU$áIšù—˜ø:Æšßq´_¯#Óyñžx”¢ "š:G;¬³j§ø&J—×ôr#ª…½>¿¡¥5@/²ñCŒ8FþØÍPC,¿ÕJ1îDÒˆg·dIÙX¥±wì Uâg#?óÕåv6žw^E~»Þ­Jp%rÀUÓ‘PçÌ⟕Î#ÁD}°¯_Ò\QDë5Ì´Þ ùÝ*ù=•Q’bÕsU$rr…W|ú˜h(1:bñ‘ªãã;^Útλn}Øåç­Mi8ÉäÒ¾³¢Ž“ÇK“ÆÊ<ݸñNÎù¸»ÅAÿóRꌂ(oÈ3FµZs\Sœ³t€Öi%ŽU ×Ò¿6·Œ‚s`m7¸ñgßÕB”a ¤À¬’A+ÇQ¦1U¾¨Àùé/6Æ †ÚÈëJÐþ€Iýï‘ÙÂ0˜xñâA¨Á—…ªM`µÄ!6¼ŠŒkaO«kõÖ¨ïÛ¾yxØ€+"@»¢m‡(p×úÃquR_Þ(™½N 0•(¸¬p‘Kckä"#`fçÞîïÂÆAýB\lspûàïbSn,ˆ.l€GŸ³«k-¥sÁ8$;𠪡4œ˜F‹2ÖW‚{4Hc}ÛðÜ`Zqt ¬”sYÓŒ20œ›söN)UÌ;T˜añŠ5Ë®XWeýÀúP‚G³áÜAޤɛB‘X q¹¸ÉÄç˜x­ P‰¹^ 4Rà(ã>âÑV-Ľï îC*^=NˆdôQ`Åä·/S“ÝTﳜÓî±r—©‹Ÿ˜=´×Iü-¯”“zê*³}ÊÂiã$róCª›:Õ‰”ÍAý dñ‹*°ß†j*·²¼¹¨–|.Ù°ÛÐMM¾ç¦r3£ã˳tyóEëùQ¨Ð‚(ùTÊÅSK\M†#å,³ëT‡2ÈóXšµèe©ƒ…py€|HŸBZZº!vâC‹óµé=eËæ=¾|þ_z;|ùý¸Ð”‹¨ü”Cw.9£õFvGä}ˆ’ÀÒØlð:ŒŽ‰±yÆ£{XÌHm»ˆ.í4…%‰dÖ±9[í¡‹¢,°†³ O# ØY¥¹~Þ%¦?ì4Ô]Âö^&®Ä\™{ólt–ÝγÑÑ¡¾¬9Žn§ÑòLç”°UÞóäŘvPo¢ •2Èq•8²Ç!H4©&oéV§_SÔ#Ü¢œQó°yïghgeOOmJÈS²íP@è—mFòæRÞ0ÍÄ÷/n’±Ì°VβÛÕý"_i[La‘?|³¼ž®–és·óN‹<œV~Gý ñ?µZ y 2Û¤N­À6\R60Tì±6zN“ItÏG§7hÞ©LkY ˆ2#i–óé.z<œVIµ§õÁ'Ù’M5ê©K¤Q—¤§Óóe†½úa«TòÔ§ÑÝôk6‡NÄ&Â$xOmÀžÒC­@£0‚éeÇJ·ž«i±Ös¾œè½©êwD|•á4ަ­6‡‘–`ì<Ȇ|Y¢²Ò$âÏ1¬˜ÅÕÈ÷ÙêËb•EwÛŇ®X¥6fËÔ0»…í^~…géêË4‹zµèdš]gË­¶—~£'¢ãZ4ú’Þ?0æ¿çÓ€£:Ê42Tš_°bŒÀl¿‰Ö—öá⨓ÇÑ:¦0òÃFµûGoë{u¸x£qœ]/±nWòîm§xD6²¥Â}H—),0[æüs_L> òâH”æg§¸­>4ç…ΉȈRòàxip8~¥ßÖD¿tEÑgôÐ:`{tؘŠVæbaœP++©±¡Ù{XMC8ú秇)‚ÇãvÔ¼bœÓuFWùš‚‡±~ÂþLh_ :|ÔäíˆÞ¨„´—uNH —µÛ¾}Á›&Ï Üø®œÊ +Ê`B©7x ™„û¦K„ÖÇZJw×î©C¾èu1—@Z§f¿Ô"­ ¾Æ¬ÌWÚî›eh—iÃÙ ¥xœ¯¦3ß6*†ªÌ5:UÆ%O‰‡3,lA[(+K­ZX /YÈ )®X° Nq|•ÿêX"e”õK¨þ$”ÕŒáÅá%©y.«AkŽ©_,]©ÆÅ1ù–À'esAÉ ¸ÖP+ä;¨Àæ¥)A‚S«a}˜›Õ#Cøå:óS´œÞ}a:•>À‰ü>®@,ÈL¼"îG(šÿÉø^Ͳ<¯UC  À¸¡@m¦j+¤l0¸0¦ £Ï4Õ Íx%Y_²õÄU¢eŠPÔ3Ü‹¿‹Æn<¿×¼šG•®Fß²eÉγVÑL óº8S®òí¥_ñî+sŸ&—š-`¤ÂÓ(±ØÉ®EÇkX— ±@ÅÜÿjì[xïÑ Ílu鯳Õ7„Zö ¡»ƒ "š N(Ñ]O¦9ðP7+f3rŸ>Áv/°úlJ2Ü-èêdñ-£ÜÖœ [Aâ@ö˜!0ßsñn©*­L0ƉGY2‹‚ÐwIºód›¿f¦'½>—ãªØZî·BTÞ¦¦ÂtN¶¨EaFEÜRßmˆ4Ár‹ä‘9¨ÜY›³¢Dò"†‰4ÞætOå~Ö+ÀWbŠ7rûsÓ7—}I­ƒÞöª÷ /µqÚ£¼fq‰c¨.P¹y‘Œ L=¹C¡¤ü’˜: 'Î}Ø•ZýÅ"…Yr¥0²{JW¬Ê"2c÷À®-°‘ÊÈ0aÚ»H'dÀEçÁËò1ÙyÁ®`6v?°ŸÄëâøØø%1áKHÃoñ%Úv‹Ôt¹OqËÄÍ{cøQp ^"ÊJèbÁ³A 8N"L¥7ËEn¹plpŒpI‰–S”Qدµ½¾GÐ$ò_¨EWÌþø÷vïšt?)íã Ô‡þá êk,ݨý©£æ€#óì {Þ›2Ú+²¿âA_qíxûUS¼<Ãú6­jl`*…b€«§Ðš!‹ü=Œ”ó±4¶þMû)·/-_‡1´ÜSË­¿µv–$lgI¬ê»%–=y°km¯8àŸ0H,´As¹d,|v“ÎÑ¢†§)¶œ ¦Þdûkš{Õšˆž1Øô_ñŸ=îÈ1š …¢ÁyÜÔpozÃÇNIu*]í²²à3\rLw®  ·…c“ÇОGÖzó˜ArP·Í¤ü»©æ\gµÇ2cFÛâ3kè9/Ø’9ÀeÁŒr„.¾þXÊÇD)˜åÌbËÇÓ¾_lÊ}`8¢YÀZÖ\ú¥mÞ¯Û¥Ôdb0doR;ªm„pªääì:¦ËM”õÊôcNïß áˆúè ƒgÔ“ J,O¢f•¬-f_Û»Ä:H ÁŒ-Áäw°ƒð‹_Ø R<4ˆ}®FÿEHkå1Ϙ%xWn…ðÛÕWø¤ƒÔs\^^Á*ˆ› Ø€.]ûgè1£үo”ïZì¥ÙŽžâ/Åçõ²é‘Æ?û²qRÛ,[³—êRbãÝ42%‹¯²·(-5|R[áÔ!“³¶3Á"»+fÍô•j…³RF‚s˜o@\i•fúnšÖXOÓ.K|¶¥i ¢i}‘;™˜ÍBCÇð(˜"_H® Ý îöqÙ’¦]Ú4­QBÓ.™¦á4.oMÕϤjçPµÆ&ª¦ú%P(ñ\)P:rHÑ„ÆâÞʨ{ˆŒ ÉÓj %¥/˜/0 ç,½Éðú‘ ê²Q`ýZÜÌ8ù¾ú;øý,³Ô1†6ÁuŒ¡/ìã9¶¼;¨¿n`~ãc;ÉÐÓðHÞ¯7=Ô¬sú¦uÕë2ït”.ï92}jj/š¹Û»Ì ¥-%D³'Ë):;ZL¼JóŠþÓ|•ÍML ›>¥Ä_W‹Æ‰`#ÑâÛ"šLoÉÅa-ȇ ÿU¼ˆ`ZTĦ Ÿã!T„.ÜÚ+ ¥ºú¿ÛÆ-ÒÙ]v½L§7Öãôd;†" "O 汕õdп„;Iææ‘Ô ^Ñÿüýäù†yþ/ÎãJWÚ+둪ndo˜6|“OKQë¬í ¬aVï inµ~œÿ6_| ´'[EA\ÓÚ¿NQ•ŸæºË/&zö;à@ %S'NW‰wJ•yÍÑØ‡3÷²Q»=wSNV?pE˜»Cð~ÀÒ¡vîÊ~päF*IÓÉÃG€-gÙEÛp1À_˜ñR÷Ý×N(Ùߥh<ÛA”Þ¸ª¤wÐüØ‹çV§£“í tµYä^P²yq—h²ÁÓ”@­¯_³ Mv“†žã‘zæØV’ÉP &±v9Gl Ø%³ÂÕÿ 2 Ýäx}{NóÀÝ®)¬)¯õv ?æÙr/|x˜Mê-·98^HSfžO'Âd4ÀÄrzÄtoÕlRíPÏS±æÁQ©Ñiz³¸ž¦óÐTàŒ½ž?e¨Ps¨£ Ÿb:«Êªp®Û­ Ù½¬Í«¢9„¦z‰Ÿ±Ö‚³<ø¬Õyá„iå³<±0F4lLÙRÂè+îÕz¨i‚‡Vÿ0LAZ*„\ _;g(ÖÖg·Z6ï†ÒµÑ&%#YåaëH·Ø¨ê߃ZM‘®H™‡x ‰1%R-}R´iúñ?n{é°Ì¦w4܇§dÁDz‹êÚÛ]ú™´ž:R[ÿ)ÐÙO{é‰NµœÅ5:CJƒRµPQ!ô¢ Ê»@gDH²réÕ>&m'€,¢TĨ„PObQo~[*G‚‘Xs¬1©6Y³Ù‰߃¨>f^$><ý…¬Õde¦è4E“ÉØ&}&©3E›)ÊLÓG¨@oäA}§]C~VyŠ}‹aðEMJZa—&ü Òjö iÌoÙ«äîî% ƒXG¦±»¬ þUÓ?ÎQd„Á]=‚ÖŒü "“²…“-3¥¤ | K'8q̯ãö=Q@­Ë@”4"ãYQ£ˆyWeÒ®ÆF¶$ßQ —NðF÷V5ø?{…c%3>ŸÂ´–Ó;Ê%™^ê…“¬*4Lïwض DMºa 4.AŒ¡'àHègÂüÖ‡6Ú‡Ìlð‹“¢í ØH´lŠ®ûd¶·(‰Rº`‹Hx)3x( H7W¢`¹âã§înÚk-DWWƒþgCüÔ„§EC`9Ž¥Èà&ÿuÕï|ÆÖð§ÔCCùv˜^—Dè æ-¥ 2Ö“?Ä¢•ú¬ŸgßìBr)Ü?ŒàÒ9Τ5¢HÉW ã;£ë4Ïtj• u–Þ_ORíàßµb°¸ž‰^´;œœßb^ò÷vo|ðw"Ʊź‰ÿ`X@8dGAÒ,ÌΑgD/KêÊÕî›T©¢…ôt+Î ÖZ ;¶ÆÚ’b)³Ž–²ö® Ö›¨²LË’„“.TO ƒZºté±Dé9 Ë§èu¤’ ^y–ºÏî„Χ°VÝó‹]„`z€Jÿ¢ß©†ep¹Ç›eðhƒ)œ6Z¾SïX20—sW]H˜#‰ûZ’ËÈzaü#.xÎîcžÃ‰>n+ïÑÀÎΠҭž˜y Þ3ž{f ómºä žç ..’–Ðg„ÝÑÑsÑÉðô܇WÛ(Ûr¾ùWF¿%°ªG¹:Kí³ý·lþ'‹Ó?¥2I1‰²†ÝGw‡å._7ãØŽ÷øñCûü¼‰ãQ÷¼ªyxŠ*'øÏ(¦´¾lP"Àè'íQ'>…xÈ‚Á'cìb¸ýÎÓG|5€%²tvz€íØÚçáí»zBŠ׺3Ôëï}êï¨ô™z(ª 3Tep²Mfv€=Bøëwõ?Šªãv(«vªDZ²å+ck4FaxÆ"g¨;Ž>X`Vå F2ÉÎ%%ueŽfÔžRÕ%…zîžT] ,ç†ÈÙžBËý&ƒ&µÉ”-öjn7 @ufYJ”\ËÞÙííôfš±.úžf{Þüö-]Nì¥qgxX̨eMm8’€%×é«)ºšb)%yó°`Õ¦DRŸÒÑÆÉ2ÅÝÂ'€~þGzMKTÂKþîÏ3Q‡æåY­7˜¨ÃµZ‡†P†ì­¬Ö¡|íÂ&Su¨?¡õºB©{àÿ¾ þ9&í6r·p)V‚_èv"Æ™g¿¯8u^}……°Î.¸5†.2Ü~·ñYòÙ̯fmÕÛ'»·ó4Çø»¯…NUܱݞi²gãÒáÐHHê8¥Ðz9΋3¦&làB•Ì6Fl“«›0vȵ"¸ÅÚò½?Åÿ6+¸å‡äS4ë§Ð8\š(ˆÈIp…ïTÎv‘‡ T¡†g*¶\iðˆ~mi^G¡Üº e غKþ‘¶êM¶]«/yT«r£Èp­¾¸¬•*ˆ å?¤Š='‹_šÿ’ü[È0 œn Súܞǒÿ¯Ä>Llï š‡Ù0üi²ëZõ…‚æáµ†àbo\¡ˆÄ |ƒþ%!ߌjéY”}3rÈŽ´"SµíÖ~ÈŒÜ[ ŠêŒ[ɼQ&ç?Ð`J™0ü4R”gÊbÑ5ËšØÞ³ÐXžáÛ¡…_V“âÎW˜CJ`7csl®7£ÑZÊ,Ý?QWOÔUZÜ “]7k¥±°U‡§ÆÎv*ñ’ðúa<²Ú¹ýQ@©)D8±û7upì2Ïw볨•ò‚ªöØ\ñð,6Ï›Œ€œ®–X\ /øQ³¥š¶/ÖÀØßÚ'ð¦¶ðgö(ÞV+®)U?%Ý?8?­î¨/~¡XRgûoƒ0ô‘ýͱN¡?­ËÝ“"Íé§Y™ò¸ùÉX[ùlï„¢*±vÇDM´úç'˜Å•›‰¯m6ÖÑ¢Þ¹\×Ì:dÓ6¤{Öze¾/ñÈz^ÔËeZe[ @gÚ‰J™5ÉEWm#g¾ƒAù5Ù­* (·Û\ЦQî:¼ã9W/œ Ds•„ÿOÉ­^;æjä@N*9æTýYœ¢¥ÇÔ]GlmE•„“L¥,e)$ù‡’2kï——g#õ¬[½6‰\ ÏኲˆDBImÔ´P0<ãpf T(LïPKMÐéWùa¨hD‡0´ù|Öï|nYXOÙâ$yßÂwõ¦eyÂOôIIdPbd&ˆÙ2£ÁpÀ ÉD«;ÖÂøn„7¦FÐéÙ½s¦ˆI#jЉÅ`K+ ¯ך;ø¹jªù9³4 >öI9>;+MÊVŠëTßZkm¨µ"“±ýjt^{|^ç ³*¤c¼²˜¬âØkÛ7"DoñM œ ¾?h„8W:xÍžj¸8O,½ÿ¡‡ôï˜ \´o‘ºŽ’îÅ*ì‰W×Ü/œÒ~`J!Ö^¼±Ù €¿p)ªíý‡!°¦¥‰ à‰èHic-LtaŒ¨H¥B_¶t’Yê^MЭpÙ'×}þÅóóax}½Ð3¬?W[ú‘nŽºÇÇ2g&õ I— {tybAOí[¨y7‰ç˜ì×(ËÒÙ8LÔq߆‘Ê´"0SÇÉO?Ë |GEè>¨÷õœŠ¨¸ðŒ–éT4ÙNÅ.‡%„;ƒè. ‰pø^\š/†GÕ*KË- W‰ü,.ž ·Íƒf°Ký³…Ï Còj6í‡ ú$öG4)<%l¥ûkZ(¼i9T4•(£0X QöžBâ £Q+NÜð (J£ú ´Æm±Ñ}²WZO³á¡q^çE³PYŽ|Ô×$§Ñ?b éSÌ]UC›kFÁwÁ5c* "˜hÔÚ$¤ó2.ëÝKµr&æòd©š*}Ñ„M‰Ì9½ô“¹ ZQ/A «o šR9äÌÔOÐ× =1–ìI¾™ðƒ;µ7Mëæk¼È!ýžÑk-:Ä™P¹)B+$X`4-ÃV…óàÁVí‚`\¯c}ÆÊ)=oRÜU†,ÊQs‡šî2¹Çw]¯¼šMÝ‹!BÖ2'‘8 dcÀzíf:Ñ9nôvi’PxÒ¢4'´À¶­8ÆAÜ78›B>­ ââð}Û´0À[ ¼ `î<áø!06~g5~ç5Nª-óv×bÿ¨a3:M|%Ñ)Þ›½Ódמña3JÓåTqZÝ•7»Z½$ÚÕ@u ŸÊ$¼0 ®3ýP|¿/ɽæ]¸&®ˆXl”[¡•W˜*qd¿OW䢮$(»^0b0<%=&‡÷ûtnpÀtö¸|QÝùkÒ”jì”ÜiökÒÚ ÃUIƒ KªáölIäu#¬yaÝ £Ñ°8õÚ"¯“€Z†:0J™×¿¸×!Æ{>0JÐ×êf(e'½©îÙÌEŸ*yT!gòH %Ù´Ÿ…Ú¢„o3¯5jÒÿ-ýn׿óƒA!8)©Ô'á}µ z¿I1ÎT²e«•à¥ZmÈNoìTØ&@‚½8)¿‹.ÞabèH Û¥Iƒºz K s^ŒkèfØ_ܸ2©ý èÙ™_¿Q8³xŒÑ ð¯ O’:¶Ñti" uÓ+6 .ÌjíþQM*Isø'ˆ“¡Þ9ѨŸSþ°*žàÝqç˜ûØ7¿¿shÖk‡ÏVèÄ$>§cT`ææ7ÉKÇ —¹Ú—ìw,è¨PÓj1Ë–)ÇKÿòšˆÚÀà¿]GÆèŒñeÐP ´ëî½~ÝÔ˹˜‹UÌÜ5Ï8ú-ô«DR)Á³d!B_ ÃÕŒ*c ¤¼ò‹â˜Ê /ZJHÄ7¦HÕg=+Í;ä1žÁ¼®¢QÊV€o PÈy‚µÑ9¹Ew¯¼-ÿ«ÍÖ:Û;J)ê L+ª &!÷ú÷Çt¹b‡€:æªÖǼ¥CÍà½àF­¾L—œ›<¼æb!Í¹Ž’mÙ6Ë¥z⦠*l Îl¶ç§¯ÛB/ÇÊ ¾Ló/¸Bè”cºÊ£æÆ @ L2uëFb <åñ‰É4ðùKµD ôhï³[웿œG€Æ¦·O`B!èùÄågW–72„¤ˆ çÙ»“êˆ[·-ž¶0­@;M¯ÔÓâ9º÷&¶’J):eh|!Ýmá pßVµÌÊeìY+ÎCUÊ Òò}|ÒbóÊ|à r?ÖVÛÔ%ÌQ{¯ñYXZîârž9%×Qžã´Üwu™ Š0:Ö é.Ïé¯ézg«i_+Q!R¥­ ì½:×nPƒ·&Do4<ƒÿÕÃÈ;»+NûaBô(ÔN¥>·?b¤ÖÈ€ã€?¡*¥$(€Úƒíšõ·õIá!/ŸáÏöÝ÷K_RI‡\u~“¯ÓÅL|mä¦ ÿ¸@Š } ¶#Ä´¹7Ë.ÖÍ uÇÌ_.—6Õ_\ýxó¡Ì‰:^PsGð%'bÕÙ8ÝŸÔY‘‚Æûùf­>O7ÎZ!¡°¾_墧zDóD„÷ð‡áàÄi‘*†¢;¢ç†(àÆ†= ¯^ñ0Ð’ÉÕ³$°Î^Óî@GÖ•wào€nlRá¨R1¡<8Vo(ÕæE«^ì ‰;9•T“´jNÂsèðŠ F”'O¸•#Ë \Td•J·ÇYËýìw~뤴ugsë½ÒÖdÛ¢€3ßqÖï£tþ"pmч–ËTÓܨÒõ.R€¹l0Ê9@ùåô†,rÔAìA•œ`²ÞLà¸OCï]U_]EX§á¸}ØØÁ±¦V¾Ì¨«f÷XfáØ§¬d]{m_1WXßEf2‚½rŒ Æ{”t;uÑ·0)¡'pEû¸«b¥ºfÆLeý1±H2'¥HI_8 .¼)g†Ê¿ øP«.5 ‰»¢k”üsŠl"¦Ï¤º ¶O íR{zŠÄ?$ä3Ù0žcDj­Í2–iûO{"¡Ì.N&á! >²Nâ+;õ=~Í€U -¿•û„Ûy“ŽÑSoLlWÅ ÌIðmôª^{͵©àüôŽ>Y­^RgÊÉÑíüh·d$ô]“d"‰Q–gS‡à&ŸÐ;Ÿ"´VÑ*¥7ä¥VknåÚ9<º:÷ ”4š'(æÙð=Ô|«ÄK+´ÌD$ƒˆ£cNÔüs¬ãŸÚ?üÉ ]å°³nY¶RZ>“¹Ý‚³}îd¢³)çQ·`PÂtÖÕz†îû§äÌœÆÏeœêßWiêóxD|S÷ó8brÓ6þs…Ñ/–“gYº"l^ž¯ÈOO¦ó“½h.£B®qšÓKáåZáò^€¥lG Î! ‘Æâ[éÍÍbÉ. ø]oq“áï 2$¾ì¶ùÕŽ0 >oå$ÀFÄAµé p$¬s¥8:r µeTªýkò3>ŸRÑâ1\^þ^é`ýâ£Áðxì Ë{¨½Ûô]ÛùN²§ùå|æ4t&,Û©sjà&T³†,Ÿ2s®]ïT»¿4Ìc¥µy[ƒ C”·?—u½ÛÿÓÄ‹`Ùí”_izðE®4ˆHI£¹á¶Êp/šÁÛ*’RÉ}¥‹êÈ ê&I¦©ÓÅ#Þ½–3ªK/ª “I%†ÇùµúÚûák¶DA@B1XÔ´&“”º²9åZɹ•¤ÏWì'%$×nIC‚ ²»˜²L%š²³ÒÃs–ÉŒV,І'ò-Sóù}lüaÌû]ž·â… mçéy±³û~´ÂäÐÜý$Ĩáå—upÔ˜åÜ>§‰í`Ó›\éÏRê’=¹è“Z@ÇÖóê{‘C)ÿØÝ Ð Ù~×!íS_ÄWôÏÿ%Ç TÕ¾%¥ôžR¸üÉ轤•y18b’ýÁm³° çØA·¸‡Åìi¾¸ùF]V.þ¢5Ž¡š«ýDnÄì€hr§2áÐT:|zŸExrè%¦î¼Ö_ b;¯8Ð[Ì^â&Q‹ÉW4Én•î… •«~›<¤y.¹¶”w0î–•ݤsø¯%ÓU:[[d!·`ŠÙ ä§Ký€2ãÒr­ª»â¯&MA èÁt%š'²|Ji§K£®¹ÒÍ,Ï´‰u"’<ùŠrÂîÁd†#=E­ªºÅk´M·Úõmû¾YH_¨š“/UtAn†âÏJžu%i1‚•å‹Ü´Bé+)åŠ.Ž hÁnõæVÀ6ÌéÓŸƒàs6(~SxÀJÅÙ›ä ÜHÌò‚‰X”N›ã ð´ö.]òâ³–4lWE­$‡Èéº9VÝä*Îo”\€#^±?œzã!1ÏÕŒ~Ô:Ú¡f»‡ÔäÔÉÅrØ:ä_ÍWžW>¡@>$®º³Ó¨þ)ðØ'DbÃçǼÔ?z¼¿ÒHÂä·aÒ-kÍ3A!/XâYu!èÇtñ#ªÍdžU¡šÈÌú•®O‹-i’à ¯CÇ`åÀÞœð:Ž*vIÆkd&&ñdux3QϵËä"ÍòˆŸ~£‰ƒ¼æÐƒ­[éòÌ^«\5[W›™)þÚµHfk~dCfk©»È@í¼òG,š¥ÒwS Ò, ÀÎ)÷]Wèõ-ïW©……Y_…˜Óò¨Ü·z j%‡§Öþžó¸&;àÀW'ªâP íß°}uó…AÄÌ I?áZ"Í'‹Û[k[;z¤(ÚüÈpÃ#Ä©GÆ*¸š|ü)°tab¹ñ{‘«˜È)‚ªÃ«a’kùª=ûáz¾4HyM_úXÈõëff³°nå¾­¾•CØ= Oœ8—ý ͉ã·R¬—lRÌ;rÍÏ6TöLÔ©ÜÌË:x„òȵ²à¯P7ߦ³¹•¡yŠñ¤ñ§S‰®ì¸uè@mr.” w¿•Ÿ\IÑš±=aÛžÁñ`“œ„²ÛlSž!Bö½Õú?kr„Û%qƒÚYåFUARÑ-‡×ÝEÔFÄrivÑLëz‹k[7¼ÖºîçÚæ{‰¬Ý)šªWZtÓžÍLztòÿ»÷ÿ„båCÀŽR3œ.¢~ZéÖ+²iÂ'Ðh…½˜TZ6€ß·ÇG1©@9²¬¨<ýô#Žs¥Eåýò.0,Ö’/Z&בWª‚BÊÿ£_B‰þûÃN+iÄQ¯ oöáÍùe¿;ní7øíik¿jI’Î#ïçŽ7©,¨ydŠuwÇUóË©õéeÚäb¿:…9ĶÓHÎHÀŒ&91m™•‹Ÿ°Ê}SÂaG¬¥÷»n¹ohbëMOEç}ÓÑ‘ŸŽâæzÙc§f[óü°˜r!.ŽYTtFKÐ`ßMȾŒË6‰˜(tXq³q§ö’½€m¥„aVö¹Ì) ¥©°pY&ðøäëÉìÔáé½å½Ñ÷mü%€™ücvšwÿ´£’B»]çèV’nÜ: >8‘Ô ’똕²Øz‰: ŒÎMtQ¤óÚt†¦íã}t«*؇ÈA­Ô’êˆÎχ_ï«u-x¥ýMš:Û4 pö²µ2ÎháD£çhÛh"Jçf·/*ܸL¯µ= 7ìå)ɇà@iÃèÚ²×â¡!5þªÙdBYIHôòùAÀþÿ”Õô Sf[׳wÀH´¨ô¬ˆªc›Ã{«^6âÙTƒî%åV=ç+ütG£Þ§#«Hª Ä# Waµgÿ¥µž¬ï ª:Y!ªž‘(;£ÑvZ½{*VGÖ€ö»­ä]õz£‹ããÖ~ÓVwz<K«L•›ñ8—¬ª< u¨ôôA«BíX„h ùP_õØ»îàÈÒB‰Œn¥(nˆ™( ©˜psSÈ®¦+/Á0«Ÿ.$£˱ÈáôLe»ÙJûX²†Õ† ,?Sÿå}…~’Ø"¨f(ø©ïW âÑ>j|˳ÔÈÒ,{ÂÙ ØÓOÅ?;ü3EÆžÚÊ=zˆ44­ª¥V g §6[,¨lD´›emP¿k´Èø~×JJOj§Ï‚ˆön¶¸ÆLv+$øwOœá7c$¨·ë¢wtÜWëò΋.®IAr©¬<1p±ppú(y ctè éI þb!ô*E(éËH¥ !¦yÄ,@;ê*Òµå;+m†N‘B9Hé¤#åâì€:ŽðŠ×mö‘"ý-qGK¤¹²ì™Ã¦PiO-öÎ\™ñ~N€)˜Ó} Â^$7¼ ‰Ty 0í0½T°‚V‹:ê•u;„Yæ'œ&|„é˜r³@G¤†¤4NÄFà™2á‡âkã‰ÎCÔu?+e¨4Á Î{WéIK†ÚÛ0Öþº±Ö©MûÏÑš®W›ziÆHøÿ:\įm1Ry6ªÒx‰r"_ TjdÄLå=¬AYA],­ßWÆjmA›Ô‹Áʾ.ö i$z]Oïà¡sò?FlS˜¸€CAÉn&9"ÿ)i§t@¢DŨE1ÓÙÝb9]}¹å<®h­tóN—œ-¦3®²†Â¨õX·ÎĤT’h/jpÍæa¯ºskºŽbÝ’í›õè¿p{ÿ‹õ‡'–,¸­<ÅO©rüßí”# LýŒ…Î^5ª;Ä%E•Ó=Š×γê·Ê*æg0´ 0&5¨*æR…ÁDÃó‘âóð‰8ú 9j+í´èÂ56W6Œ¶OUyÌ·úJ'e'«Ö,îAdª" W®¶ZmC6Ë3ZC Ó&Je°¶(™@ý1Ó@î+j˜,Á^©Õ‘Vº ä‚ã"ÑX7ƒ#{g§;P2ËN£¼œY|ÃyÙ„:»…üºQ$ ¾¿  ²DMü»±U¯Øzéü·ÄšÜÞºi†é¥·y­ÍZÍ356–z¦8жú¥W)ö°µ¶¦´‡mT5/¢¨Y§¦‘œ×Z)]šôšæ¡ú\e»£vWFÉSªx(ü²˜Mtõ+‹a½دGJÒ™>w(/öãYãɃ%ãÒó9­eµ¸…»R5óf£×3úáÅ9«îvÿǵØGhõKc ›àT•ñ1-âhQ'²a;„s äöTïJ€ÒØ_¢Äf‡Öô#LµsÃIó-á {¼rÂQ¡{Q(x*)ñˆ<Ù‹E6žRˆ”õã$'!FIÜZ[Haˆ(UíY#RG\bøövz3…ÝŸ=E“i½Þ¬ìÔÅ—#Þê™”²ù7dþ, ¼Rg>×þí B,ª¯?Ç‚QD=G—áðs‰w¤p¿ÏÕº:8þÎÓFFuȉW€§I[X¢ŒX)Xì3çr§êÝ€Ÿ/õ¿TjÅÈÕ+ž´‡íCÔž>ìÍ?](Ï` ýÖ~b”*‘xÎYu>;Yé§W¨úÛ;xE¼âÔ/ô䫆äP—&Ü?é¡è­ç8aAšt;øOõ• DÜî ––€º`M/“Âbáñ¿0(Eð”+ÿÁwo˜Tÿ¢›‘ØÏðS.b·ãè]$ÿºõÿD ‡¬ÖÓ­m±–ÓŒJP ;/Ÿ\1±eJõS9“ÍÙ =½'Ž/w—¿µÚZéštuáÝœ:‰q¯áX ‹e"N|È8?ýã|5Å”LÁa^]°~OiÕ.¿eäœ9£V ØrÃ^<0^U–Læ·ÿŽºF«jE`Y^J‚¬# =½²€Ê½ôw‡Ÿu(KÖ$˜€36 (~¼ØX.ŠŸ›{à ]CØ{ØŽv·?Ž>u/zµØ¾„°+ý£Z *]ûJ–\Ìf/fCÝGÜѵw“_á<å­ea$¸”’„㜖¡aB)õ yJ·ÉQo€VÙ,¸CØQNGã“sØû–LÙ \K\JL<`·Æ–Ðo-êµÏßµ7#ÈFÏa¿€ iz%ò1àûìnjÛBïØ–eAI\Œ¬c:{ø’îiµ¼`@xò:»Y`ˆñٓ̕DÈ¥^Q‚¡ð/‰ºBùN-qcb“N"„4ÖzÅ¡«ïüì(.ƒÚFìm`YYl]£Þ†ˆ£GvP³{Áú ïjÙ·Åq](5iÖ]Žb ºù±‹¥x±õm ¬t¸ …«àпžWŽ©Â#Cõ éÿðËÆºqöqܦ;. GÚù33*dâ­"S%3b»ÌØí Be£](ð¥Àþ0j»7¸œ {[Šª)k‘0‘‡¡’ È€>%‹U*1ÛhòRóEè*ä¿.Šø¢%Ä$ÕÒ§ú1±>$ž=™à5 «>‡àÁj§ý©Ûÿàq¼±êw4’^ øxû!?ó³w»TÐTGÍriu)ûÙ˜‚ÆÃôb•8/\¡Ýž@ú×*õ§#FCŽ$­Ì)×ýSÈB#dÏGÓ_2ˆJ…±h²‹js6 %Þ…£R_cQ åÚfÛHÙJÔÐ{œC¤{\‘D•[Á,£Û1bÎ:Ub£9ø61c(û£ØŸÃbÅ›«MR¹­>{Xfún¡ÛJK¦ƒ”5J%<³«‡™HÃ~¡(º¸Vº:ò÷rn2ÿ¢²›)Ü·t6{ŠK¦ü9Õ\àØ„N¸€Ú¶¤ÃµØ¦´½ }ä¯Í¶xžçŽí0ö[Ã%L>„®—4}¢ -Z%J—\Ô| Tþ¨ã4Ý5íí*# : ¡3•ƒÿ AÓ¶7aX/(`³f0*U >W3X¢,s|áD†:$ù'Ö ù| Ž]AfÛHå—g/ðÕ~x/—Æ Ú„›.ˆdøâ[c\‰ì %ïgœ±¸"èë÷âka à¸Jƒn’¥.‘Âî^" h“‘µS/ «ìÂ*ý „+Â¥æc¬'oÅ[bÎpJ&ëæ"´ÒF&îòðÓŒžöÚ£q¬ã¿½\„¦!ÇgžÂVJ6³A÷/úý·¸?¾t6å!ÄEnùö]ÒHÞmàw)Yÿ˜èJXÉÚèJåëWcIÑ•ÊwxcŒåÕ¿ã%ùF>'þ0d}ôB7Ä#ŠþJ<‰.Vb¬!' Ê)”ý¾rò›ÿHÖ;DpÒ²Ë%á¶q!ŒJ-±ðâváVuÔÒåðV’ÛÝÔÕÀî‚цº´†TŸ/ôŽ æÕ+à ƒYÆç2KïbU;ïú‰qEpnxªÔËv¯ÿ q«œî^‘‰Y.¦»§…\?…æe¤¦ ¿çˆBv*g»I5&+ÔðLºrxZ`ž~57¢›îÜ”s`K€¿•áîL $ôð¼}y1<ÚMDêãk'ñÓ’ vô¼t`[zsóxÿ8³ci×÷ñœ`àÐŽãƒÁÀÁk޶ƒC;?>x ƒÓÙ7\¹Ü-ñyöúO^˜†TóŽÒ¯¢<`CÌ:N5Õ§Z {QŸ jhßPP””ý’Îï¸*ô5ϲ Ae¨Ý$»ÁÜjÚë’ 3º1çºÌ¾Ò¾XÓÕ>’6È´•ƒÖ$cÓ]ONõn—ƒ…JN°48ØÒäàIá¥+!¼~RxêÌp?Î oÈ;ZþÈìoŠ9sò/ÃɃ἖òó« R¢@#6›w^U’ÚQ}ßVK¦KeXf ÀÁzÚ0Ýz•:·N™½üàÆéíåhh þOÞÎBßI­lâQŽ®áÝvû.YÌÅÜ"º…ÈÐ §ðø°‡®›A pÔ‡KÚȤŽåScØ©ÇÜÎ6jNËôNhÁ ˜'%³Qádœ—_¥ö޾Êô7_XÞu%Aƒ5O±?¾€ÄH‰A n1|Émç9›×úß”?•ÄP5yœ+Z­ñbAÒ¨°'pÙNúXR½Â´`ÀÙ¯a@àÁ1ðˆ‚—už3B³6‹_>òY72°ô8²×á.ÏjA÷g}IY0{¾~A,à½04WMþâRo /eûG׆-záI¡6[á¶í%ú˜7§¬=$Ò ‚šu5ˆ¯ªœ‘+ÀFrè¶¾\ä9ÍQË•¬Ä>š@ù~žÝ!Ó1]=…ÜÑIû¡æÐE¹™L Ý<É êÖŠ+*{€'Ïÿ'°Æ€øV^ú±Éîú]É]£Èíº.ö¿¼¥Bý£2¬Ò³Ç Œí@ iÊAX9;•Û‚rÌTÇš!]܃8Q@*\¸Å5£ýÇ<½Ël ;ç¹À4î¾Ìž,N„@?ƒØÌûRÏØ(=\Ï­žøüþ€“4ÓÃѤŽ\šë{•ª¤órÖŒ³ßfºöÏÝ=0‰ML§Š£ØýjÀ`|Ñ#W„ó=gb޹%fÓÁ:C¸YúRJU¹ n®Xä–%6d‰—¥tŒ4ågwÏ ŽONçág_VÁô5—^öÝ÷rÖ«¾tŠÂC:õDçÇÓMXeßHîþ἞ï¸W—”:@&äüû«ä•<ò ÝÈé©WõZ£ÉÞã Ÿ@â¼}RœQaC®•Tö8ª0•z¡™–§§ @×_)? ¹·]r„± *O7ŒÍûkú3b±¶Íw†ñ)›’òŽA–H‰Úe30鋵^Ý_Ñ›Fs(¨}#Ñ×ô@õò(r­:Ñ`õ•|Þ•ÏÖÓ ]#–ÚZ{qxúŠWL¦?î™’Üš>Èjq#¸ >\°«–pò¢6 ÞuLð¶)]²“*]ª2‘/h’ûGddˆFne—e’lê´Î'Ú1 Ÿ[)9Dù—¬Qª€ë,/éÔ–ÜW^þ‚@½â’؉*éT‰„ïËÊ9RF¬Ïhª3ZÎófýn—±èiÕªç¸ï 78†SåⲜ2…Ö ¼ÃÒåu èõ×ç_“*ø“Š[é:=NÅn0)d7ö£¹ÕbJ3yG•@ïV]Ç3bò F ¨Ÿ!Žj®Æ'@SäPF’ÉÂ!ÇnNèx¯±.x$¨¹e‘Šg¥ï¨t¼A_·íR„GB3Z6Űp YIùÑYÏTììâþ.ÑÙ”h¼H18@LÓ …ã]ÇYà·B&y²Æ»ùÆÙÖ^Ø;e|7&wcW'3;›ÔG1M«Ø^˜dáe˜•¡sèâÖå ÿ06U6Ûai5Æ!ÿKŠq ¶X†A¢ËLëè3K=çß%N}µ|2Ñ\ÜŒzáa;ŸxˆÁðS}?#Ï·- ™;‰†8(ßôµß®a½ÌþþˆE¬cVVØäÇ´Î(öÍÈmÀ­—×:Xd²{b~O¤qŽ’^MºLþ¬ŽU²Ø,¥4~:[ÀT$Aņ.–n< É™Ú[£\äM¾U¢êP<ŸIþ$ ‹yÖßXA[øÉ3Çlar¤N±ã˜ý¼üe0i@À*¢ü{NÓyëLç­@O…þìéÉ9îÄ’ÒJqL›Ó¹÷ŽVÒ)4ãgU•Ð_ø®Ç™ã‘êªðü4ñÀ—Ý×Ïÿ6@°ý,HºòŠ ¥²„—N>ÐO•§€ùO¹}ëÇšêþ²,Ñ`á±Æn>° H¨‡Þz÷œ’AiÌPÈ¿&}ˆÅÏ`cõ¨!÷¬mIÁážÖ`Úbø|Ü>Œ·Åþ%¹ï¾§U0?~²ñ¡z½þ&q3íÿAñÿí²õo—­g{>ý/O4ÿƒþ(të~Ô!¥¼“{¤Ø)QE{ãUíÔ|·=w ÃñO7ù:î(ÕµÑYO§~œWwÔ÷üjûc3IJàõ“5ÚWúRæüIÈ1¤pJtNÅgÇÖMWö 2Ø8~ìºS2ÖH• È̆ìjÛä2ÊíTìÜÀ}uÜotTkŠü“_¨€- ˆ¸Â®Ž¡I6š3õÑmÜÓU3k¤çN¶OѸعçÈJ†e@.«éÃ,ìU¨²AóŽDÌ¥ ¾QT(mÑ6íÄÒ¹¶ÁV"èjJëƒ9ìIù«`²¤¡›$£ZYàIUV»b*¿¿ö“ðµ”ÿËïÑonüº›éö?:“©Q{«Á·0Ž—û»¡qܘs·1Žë§Ÿc1Ž}Û„üœ‰>˜†ÿgdáÿq{çIôµ“²é›|ò–õDcAJ“÷â•@Žvò[[ZÌõ¡, ”÷#bŠX*L†k¥LRé¼=ãŽìðÆôî¨L˰’^ŠuˆÞ5äåúÉÁêLg\ë¤`÷pv"e<1Š!c±4UúíŽ`ÛBDº«¡±U”YT)0Ú~˜nfëß”ï¾kôðbîD¦âî”ßgª¼Š£Nl;˜;f¨ƒ23þ³çé¿Ôávœß°nW´ížî蟕ޚ&éóZ[ªÿ(ÝzÈò|Ñ; Ô6à&Jeˆ:,f;ŠÕ!ý”dΗ†¯¸ïêΫþ_Wî9»9Ç ¾; Z&l×]6:Û6f?ÅÉhÇž±«ä|ãê§7œ ßF+/¾ÖMnȈ/Ïóâ·ÎwQ»rŽ©?JâwBr¹âœq‚w Ê“!:ï5™ïÿ8ë ?N”_føEóܪ‚mT°Sꛨ©çè{¿;í}€É-ÓÞ?Cmº^oºÙüwÈü´;F[).Ñ‚âðÏPƒÖ“Í@·RƒêZ¢HMzÝÁ§qXúºþ&iàs‡dñ™èLÓG5@ŒÓùÍ2£ì$ÞÃFUþ»Zý#t¥c‹ÑS.yÐlî[ÍwŸe3?ѹ0dŒ)1^‚¤N †OR¨%–«dqŽnU”ž d8¥©€Ï,˜-1ч_ýýq±š{\襽4K±dX[9¾•˜þjQLkf[Ûée[nf¥±ˆ³lÂÒ½îZëi×¶±TR-]ËÔ‹TjUà&W‘}D‘¤B—ÅØ;ÖâíÒM´Òª¥’s˜"‹oC^´%†2eÚŠ­•Ûôz®ÐDµø$Û+ œ$[–p¾%`k½Ð+võ:8Y–õÚïUâoKü’(×ZxÐs«%©÷Ê Ùâ JÑýza–Ȭ²=ÃîqèßÊ™3¥D$,©=,ûËÏúÃè¯q©`cJkE1O Äê ¶ÜÁ7˜|U9ÕßìhÍ |#.ëgðÙídÔýÐGíFl7q¡~wá]uïÊÑ]a¨DËûnÀ_ª¾Ú&ìÊnPtFfe’ï»–î£R¿S"ÜG剺ìuwûŸZ¼qÎ\ðDõ¨''Ò0zC˜žên¯Úªt*=¥9ëU«;Ü}ôô¤9RÞÜ:õ…µ-ôu#ñ½ä b¨!ÀâžpŸ7CCÚ)Aá¾Ê&OZEÄxx¯ñ?ÚZ’5Q®V›eKü<)üsQY"¹°˜ù}£ò-4|´!›”Þëƒõ÷úÀ¹×/s¯Ï;ïÛ}Ày;Œ°zÕ]~óÑ€_ýf³^\Évw¿Ië:§Ê‡ß[çÝ~½Bâyxs¤ïwUæ·¤ÅhmÎ9Ý?Tš¼¢6fŒ.ýâïm—/,ý¸{nA ƒ®Ï´Âø©y€Á I £é[‚_Ãõ[§Z4s…¢³VTéïVy†V®mu¤4™3Dýª÷Ó@ÿÆ7Äy -ö}´Ø÷Ðb¿ê÷RÄ‹Åg¨g…yàÇ–úõ—¦‚ÖHwefï#»õ¸îÙ¨n¦Ã“ÚÿΓ¢UZÇeÿ¤jŸÙŸð¤Ê}ÔMp†õJèëtÝmð¥Å«ôõítŸé¶ú;xQ÷¼Ë«vŸbxºIÜmüÒ´‚tpߺ»]¢%–FÓ’¦`sMšå¢Hn£kÆbDšÍz¤é°ÀF,†6ÀÔcµ ©³Þí0òÑÏàݹ߰v¸Ü.RæâÓÿPe®<äjuÿ`eì}:OïTFe嘩r Ùɓŭ5]NsÒ¸…]Ÿ´ŠbgÀŽ3Ú£’Ci©È›¦ §ì^gs%µÏº\³Ò:/iÛ5Ñ)¹#ípOê«nÐ><Ó»¼Ð¨GjdÊ<á6—{²¾ý{¯ýKjгgóÀay•ÁýGäU- ÚBè³$ËçÈ‘k%GKpuV`p*b_u¡cøgðùÌŠŒãžé§0#×Ú‡ü‡£%¸öx,°OÝRÕR»Zª`mHIK ÝšªPþ-‚ ÞÖßn|(aÝÆ0»§ÒÔèè•Þ|!U¤Æð¥ÚŸ1Ç¿ºY´uk#*ÖÄRH'”+`s,ºZSK;£ñµa­$ÿÆnîúÊRÿW¢fåïïQ§NßK-,Z7ç’¡–!°ÆáDo°¯ÝÙòi¶øêeµSeƒCEÿè 4÷iK΋E~˜#Võ›ÙZg—Db&ïX´`•úÍ—, ÃLÚ~¡²­ú©CôslF¥<Ø4sÿ˜¯xʇ.œPðVfÄåÊQ½O@­]rÿܱ+ˆÕä¶H7¼> š›WO›PÐRòÀ1!CÒg&N6e&]ô6€µFBFA§òÈÅM¹Ìõ¢­¢çÎ+°¼jÊz4N–=rœÐ'e2Ú©Þuª£Z8uKá` íY/eàuß]2ãGò0!W-¹žò­dH˧wxh_—e (P*Ä©`Жæ¿MÈ;*‰Ð+>ê ¦“4{ü ¿þW ©BNHE!^Š©jÐ`} Õš†C=ßg6T|šß0·ZÆò-áöÀÞ}ßÀ?!®ëV »i$MŠÏ¿'@뜇4öÚ‡diSEzV7_Ò¶&q'¥‹>zR™`«^W\ȈK Óy ZdÈœ…mÙ‘š9k›¶õÏ­†qÑ#¬‚D(|éçà1À©Óö·B¢´ÑOc!AŸ»ÄÚ]’7ŽÃ\ƒ¯ ’ëä ÙÄÍwK¿£(¢Ï…œEò/ì#¦¼tS“ÉJY§ˆ™á”úÒqJ öœ€YgªÐ¾s+%ehÒV d¡¶;ˆ0…š,;}³âøBݨ`ª¶ÌÖdV.Ç€(÷y]'éä¿sNÇiç@P‹ÇªÆîâÓ@]*Ë÷óJÝ.‚Xšf¬Jƒy©;_$‡æ÷%ÑŒ/EÓtQ_˜vÅI\q¥*A­mÝðZf¸†;¼¶9F)­ S çï|1Ñt}ù-RP 33’(*‚Ö³‰àCºG&†ˆa9ä‚l€ãFBŸ€ârgüè{•X»ìô6ÉQõwqøyÐj¼s´€Å†ç—ýOjÃËþik¿j雲ö>´2¬j5£õƒ£eÄñÔ/ôÁúåÔúáÔòoQiù‹¾i )ֳƿ;D’ܬR›Óšy©ê6#~ÁX+~¤·X÷_’ÐîpîûN‘ÏïLÙ7x^Î> [ꇋŠüÅ"<¬ÜH0¢ª¦rZ‘P ¢ã…lSçúÜiÊãà,ªX=IŸpÈåªù¤°Jè  µ°oÕ˜Çëò[ܦPÙêÂÁêÌ>ƒS?•ÕdGsð.Ø[¼)šÀž&ß$'ŽØQ\÷7i€Iù[’üfm¯hõ®«úõÔ½4c¥ô-jyËr¡ÙppA›MÈB@ÉW!;ÚÇàNÔŒ¬2Ü¥¸P‘‚xJ`èþ È»îf=Ïg˜(¯EÐH)Êu'Žß/RÛ &–2±ÆÃ+Ý+&4Ðùô!sêrÑ|ŒX‡YzI ðúYÙž•—)x}œç74zûÈgs¾.\…9µÜTZ…kiÔß(¢R•«+KÏ*¢ø,ý&=ãÅ2£LáªH GS£·2`”ù‡ÜH¾‡ö½´o$%¥Úp#KòS=Ëìâ™àKÌ.o’ƒ m´¬iÒÆGŒ~Œ]çt°)/û%³ú'±½la4¹YÜ_SúxÉiL$Ò‡6”Ä¢¸u-,_3O»Ëãy“øÈ¥õoûÉ‹æþúCm AmÈVv„ÿÝ ÈÖkËûÛ)ËuÄ£´…­Î0:3C߬^u@çeéœô°Û)×Ë'¸A·Þÿ!Õzù°ÿ{2¦ý€Bþåìn?WƒŽº id4èC‡Ç5ÿK*Þ4{ó°…MQ™n¤¦¹Ò¨¨8ýYz=IƒpKŽ&2ƒ%µþ?Vÿ™ü‹oSa@y>¦Ziœ`f¶ª¡P½°s¶_Zš§$z¨)è¼á(ËTá$ؾZ8³ZÔ(ŸOå¦Â÷5ÜÁ>wÀ· ã¶ù¾Ôe/&1•»Ü÷‡çh õ>™¤bG€DGëMý—¶ˆmਨÿ«@±ƒ] ÞÆ`úðm®… Ü6@™É(¼tÔj$ÛÛz£‹ããÖ~rm%¶m ëÙ0e™$Õ \:J}fÙ °km ÀÚ `é %ùSbE—=Ûà0ì]Rü•% ‹üš» ÈOÍןZz4¥=‹•BͤØR‰ÇT–ÌÊ`oŠ74Ϫ;5DÕï› Y:¿b-µ¨¨y€!©¦…!½µ¥"µŽp=ÝÕ@³Ä´<Ñ1Ý_ýRq£) à–@µ‘1…à{£– a8‰½V¬ì믜À'7}Ût/°‰ßs±&æùÙ×®pìgæò|¿ p¨’âqؼŽI!0KÙwæÉsÏ™>¾,“ܺs@C;ðù‘[Ð¥pҰǃ€ÂÇ\€“‹3»ƒâk}*gZQŒQÏWú¾3·çC¶Òà΋ôe788×âôÜ&]Ù‰¨V…Äd0±|r•ÀŒÂÝlq™pWȯÞ=S„™H­˜Y]ôà:ž+0p‹HËšó²/©œOÙõ¥÷Ï…^,<+é¸x‘í;Ë Àç)›ÇQ÷(Þéañê£À‘Ö˜o¼è{…¬Äˆ)]4 öBÐð±$àƒÝ2Û<œ›ÇY”Y¤ø7Ss!n¼¾¶ÊZKh•îr{äÎýææì3éújö䬌}›sõ…³ô¡AÂÁ¥˜MñL¶4Wß'¤] ­[“©ïV¢p’½µ+F—êb¹©óôYÕtÞ<“¯ÏHdNB@æäêµä¨¾Cxº4Þ†,z ‡à@+HàÒ$¥%Z ŠÍþ;søí[ßéQ›‰õRF±mœˆÛªêÈü£ìL*a|øÌt…WÈÂÕ/7p­·pyør¼_àÿ8¦àï =FWTÆöj€LGÛ"È mŒvÁ7ŽiƒYÑ6ö–"‰7DÕë·ÔÖi¡ûW¸ñëzÒÀò0稄8–sG†Z#À±ô}ÑJkšà)ìà?Vâ À¡RÀp§³‡/©Êÿ‡Ü4ó,w,TÆ6EÒµ¨‰?WѦ5éæ!.á[™*+O©8 ëÖy€˜WªKÐØi÷'ía¯ºskw-í8×b=ú/<žÿÂÄÈ„8iE²¢ ô×!h¢¸1Ë¢wK¾KOm.j&?¾É8"`>Çæÿ?ý…riQÆ?ª/m¼*ÔÏX·õU£ºƒ£WÁçCeó3ÕF{+¤Uµ$¶ƒÀÃó‘š(>GÔ#Gmå½( Q½°ÛÇùaªë0EZ@é l ,±!{ªÊ°­\Ë£Úl–g´˜æ/)y=ƒ‡RëTd±­#³IzQ#bv¦¥))=¡tÝ?ªéȈh]´TÊÔ‹’Ò¦bJ``ªI{§›#Ñ–eÛ'ª$…zEÿrk _¸ŸÓ@6>©öuñ±kuÊå‰,ˆ×O°ß%ò0󷷻ꪕ_D©¼V¥üL…²¥=.´­:Yé}‹=lí#^ÚÃ6ªäQ$¯S#êô€R¤‡C#hµê¡w©nÛølð1LÛIGÏy‘JrzD‹ÓVB£Æn–H „Õ3q!ƒ£º VV‘Šà ØŠ°Jôæ¹CyÞ ÏOY0=û¥;*ù+æ´1È«ùn%sõÐ#oJeZËjq w´jÖÌ®Ïè‡[׫ºØý¬f¿Õ/ådjØô¼ª\p°*>ýæáˆ¼0(o§õ-Ójƒ97«·¹×W el5qBpx…ú~|°¥Ð&ñ1i”bÉ™Œ<ÙsEáî#›ÊúIì~ˆ°)uŒ6`ýœ0wUj8±F¤ŽØÃøövzƒŸgOÑdšC¯7+R2”vCnÅ G®lþ ™ªëårºWÔ0ø¾£ºÙÎq°ø9„"Ž8ºì ‡ŸÂ†‘<žkçðX’%ñ, ‘1Dú—-!:"âÉ2Rõ)s^déT½³HÁÒaõ1>ŽÉ$rm&‡'íaû­ç£;¤DáÂ1Ê.r«ë·ö£ú¼Yqí1ŠK ½~¾PsjÛüÓ+Å÷^Ñ#¯8“=ùŠËTëÞ¸ÒÒÑ[5Ýã„õ¢¤³"uGõ•Dþî‹kŽ‚‹º]§ €UCƒ¿0¨Eð”+¡c9:q˜Tÿâ:3|U ‹8ÚGïpkêÖÿÜ#§z°«x·?BïSþC œ/x,å£eJE¡Å P-çtÎîJÓ{b‰tù[«->@ø-6•¯…ª ¸v4Ë_†%‚n,žŒX~ð!ãªõóÕ Áa^°†ÒµÊ¨xž}C9£VÜØa-Ã^<0.Ê–Të·g†N+~X©¢ô& ¢MÎ)ê‹'lƒ.ˆ%LGͺ5®„~kQ¯}þþ¨½=6šx ûôHÓ+Á/ˆÿÞgwSÛº©¸+Àµ,j2÷„l*)Üö´ÀƒøO•­R zÖ*AÓ5k“q“uOšá„6Ћˆ ¢Ñ3öÑí½Ôj©š¾~w,ñ´þ±Ò¿€-¾nÙâc¼RG¯µÀ—#“Â)Á¾É>`ï-±áóoè/¼Ûî˲î]¢,XIÓ0_tbIŸ3°øœgñ4[_QB”+Z¸Ÿîý‹áyå8©jü¬¾!¥.~ÙX7îÁ>ŽÛtÇ|M{ aÞ‰Œ—¼UTÊŒ¹Ã]æ5w1¢YåDGãÜK]²Ã¨í¢ s#$Bqnâ˜*š¹)kΰªÌí-"²Pš‹†øH]H×øRóEèÒ`êäŸ&YÉ¾Õ ñ%Iµì¡~J VúÑc&Ò­aHõYR;íOÝþU¿à÷ pôº¿Ç›8peú{©½.Â%øQÀQ3ÁâZ;ÌþŠBH€€ {Ð Q&Öm{nP¤MÔà Çìh!,°ºIQ[u-<ôÍ€†>!jâ- X™—ÄF€:‘[,È´´0zMÖ£Wí„Ô°gáKÅTÕŸiÝeKXÙJÔÐë®çµV°î®£”þkåìx–÷qŒYrˉi‰™––ã›iíöÇì´ÞúÈõHRˆ;õy¼Î`ûNI›+§­-¢[ØÝÀue  U„ØŽn7Ü+Êñ‹k¥V¥`Àµë| F è!»™Þb¤Åì).™²²/J?‡±‡Z¾= ̰'/¾kË›KÎvÌ2s£É5»Iãß®Íæx¡YŽ;ö[C!h~Ôˆ0Zo¥SÊÕ‚™¹h’b·ò´5¦·)|™ÇÚlG‘°x*ðõ>i‡U]´Â˜¥§X´¡&Ñ&TWÁïØ¨° >^ì.®Ïˆ# à#<`…'Ù•2¬ ·Y•*„Ÿ¡k‚ËàlPã¾ Û‚/ F§o¸eç i/5˜l3 YȆқxiVLF™¨2v’• )eºÊtq‹ $…â/®rÀWû+ËÕây»òq à9ÁÚz<]æ+¦ DéB_?EÉ«üïËU¥_e2‰‰ó4­LoË}K—/¯*õ%í9,ˆ xß„íQô]ÕôSn.jC±ÉÜÄ=U†X<`òôÆ¥Èè/5Ò"! 0¿àôo|Û2nA ðÔ,¸‘I½›ÃN=æv:¿PsZ¦wz( ž=‘e,H‰ñQ’ –ÆE&6u•éo¾°<K.‚1jžb|‰EºIçŠÂè…/¹­{¶¹¨—aøÙ HèW-@‘{ ßÎ7K:‰®HÈ2Â%›g¿†AŽÇ8[JI£Ó#BßNÖÙb"ëFÆz60²×o\ÓÕ‚nêú’²`ö|уøÆ{aö!^5…Ü yI½ËèqŽVô-záI¡ô‘­pÛötÞ¡—ª|q6PËÖM%F}‘þ3’ÓÂØ å"çªú²°VÉžˆjóÅ|žÝ¡¦`ºz Åü:JM ‹* ²JšI¦é%slëÄ"9ºû°ÜˆŽøÖüg oéšúp®Dìç%J[|Wa‹e-ö6-7vM©P?–.êvr€wpFˆ¹”ª‰]¨Ò<§ÐTm Ï Á’hÆ’ÄH¢'¸«»%:m/{k»3ÆnŸýjÖ8¾è‘³ÐùÇV½æŒ ±â£og€¨a˜3åyå– •îϵu›npYn‡OR~¶Ÿä}ŸÎƒÏþü¸ví•¡‹ƒRB‰¹H+üÒ‰¹ ø’½Piä6>ê/¥œÃo„q¸Ê3ªÊ%}'£¨W7‰SëÖç·Óß Ÿæ‹…–=WyRøÿ”“MO?åçÇsg k9>=¥(8%!V¦—µ¨[=Õ Îûƒ7ïÁK*A…T ŨDî%Ûør·7äI¶-Á°Ð¾í+öL‚ŸÛ‡ÛSŒ’BRÿ¿°f=ÙøP½^“ü#œÇF.ß1Wuù DZ—t{¾×Øg0¿8ÓŸÛõëOàõïbG?\ìèûÜSÊš=Ë;¥¬“ÿ=õ„¶ñi‰*ÚSO{?þo,举|T—Nçøvìäƒ:¯î<¨`ú5èû4€²C˜v̀ΔïÀ$ä…RcÏðŒù—r5[xO ÊÇE„½žJvn¤‚Ë î0ÿ‡ïÈ?J‡ævÜ!*Ïîá¦}u<—T¢z‹<@^¨0QŽ$‘ ˆøÉ´'HÜf„Ó‰Ðm\`U3·ªçNvUQ‰Ù6o²´’¥°êjú0 »Zþ¾~’ Þ©Gâ8ÅÍÓmÓNŠñ¬mð£Å³ºš÷q Íà¨\}à¡âdHç êî½Dô ÊjZìAÕ¤O…p$Õãù=úÍ£KtÅÅn¹΋œ’©#Ï+Ù2çR±ÒY‹žý¬ËMÍÿK;ko±èh=­çT’*vòg­HÅQ¹v9ª3÷èg”ŸrLØ¥…§¶)1Êÿ¸¾’Y­YÒ2€i¼KŸ¢sbÔBl©U‚Å®ùtD)-´iˆÒ>EZ ÇÆ%SCé#Uùï¬âƒúØ ‰R¬)ªP½¡h×O!aÒæX… sØ)s—Ö-‹–¥ëÔow½ûa¼Š7[_½ ;p;àÁBœ‘Jªñ%¢+ôf´T¿*öâ_ª¶‘¥½W9ÑÈÚd18»ûºÄ, ;{ÔG¥ZdÑx[vMìD¿ßƒ Ø)œÖVr¬)?»ìÒyØmâ¢w$Qú{»RꙩÓÛû&h¯—¢BÒð÷]ÝÙa¯ƒWçn;—=á(ÞwGK[äÈìÇ`»-ø ¶F;öŒ]›Àךc¬›ŠqZP«BåŒöRu‚¢…‚:!CóÝ‚²3‰]hM‘ M™ç^ֲ̈́« •ÑÙ³f«ºNöqÙ…‰LŒÞP¾»@ÐvU{‚5zža5Xo6p7"Ws*ïüh»Ä@€³{†… žxñÞß9þŽ‹ØHÕšs8°1s3˜†IʲÌ9òa6ýC*ÙðQI¬A.WV… ¥¹[ƒ’‘‚áh4è~8— ŽYÅc9Oºœ’>Xb3Âz/‘qÊ5™ŒLy”_]U-Û:­u¬W_ÝY ÖK¶X-ùͤÀ·²óâMµECï„%DT¤°ÃušOsU¢=ŽN€ÙËæ€‰ïDEGÙê¦FJ?Ö‡¶tmŠçŒŒíÙÞÑ"L´D½÷ÞÊÿ…rŠ)`O)‘L&éòw<,Š“‹\–Ü[ŽH§duüY¤Ì ޳¥ßk¶ˆ¥Ð˜æ A‹G”¯7d’žD®á°´3è„c ´Â@„òz54–©Y®ôbw*–:UÐ6C÷Ú¢ÿ BhÐ=kPt*IŶ(ËBß"k¶¬àãÃÀ9jšý>]± N{÷’2hY­Î¥3Cá–„ePF£Š õÇ€L çSÁ4F₾k~×Kµ‘BÜÏ] 6ÂýaI×N+¥óI]Ò¿I3¥ûöŠ 3IyK&0ÁõŽ`¾}øýΆÀLX +éÁú{'¸½çøìPzõ0Oïoä`Ý$ÐÅ`Ôó7·×¥ïáŸÃãŽÒáçãè ³ŸwAª^'ã!)\»ŒC·­ä5¾ëu[˜éVJTCͶ,úL³jaRëε…¹s{0ß&³íÑNµ¯«/Jéè4¬¨$TŠ-´‹£"tˆt§œÝÞJÍÇ7,¶´Ì_ð& À¢Ÿ=ÎúUbÊ;”Ö †ãÑ|tOK…pVvšfõ-ªþÞëWC–¸ãÑ©𽆈³sÝàÌ$ æmÔÝÃÝ€àAw…¬´W®«²òd~AÀø˜g†ÓAÐÅ|•‘»ÈÅ@³Á®fï³Ò¦˜¥Œ’øÃ*ãíò8ŒÍØ1½·€)«ÉÝ#æ¬EÚùâÅÅ>YÒBO¾Ù¥|ø¤úá„Î~§ŸìöÅïñç]êz‡Òpt†?cƒ†Óßž0þº‹¾xõJ‚>½=„£éý Ÿ:êñ¨®V¨˜<­ã¤'+Ô£½¤4lnêõ*ÇA/çóK¥ÕsŸÚÓ½xšVAã¨È`ßrÁº±*aÅwýçeàe+f7âÛç|EIøö9_#·+;]PCó­,ã,‚ŒÅ¾×(?{i%JÔMXÑ܇…a TIë1¬‹`AðüdgŇþª‘©J„2*г¥èòyzX&ó?]çú&úsé\ÇVò<å–]Ôœ¶a‰×ÚTRåC^²|LÉe)`%ÿ ±qª€°æ‚X'†Úyþx/•2/@Hž¯–O®oJ­h°\\ÏнÆŒUÀéRàÒÑ|1`òP"S>©Yã‚ÏÙ<ƹà†TE´¾‡¶îFüº×tÜêÄqù¾rgBþ·ª‹›b:É—“¾°š¡­¼ŒòVŽL93·•!Ê,_°¿2EK…üÍÔ× ºÔ2SŽ.©F–P¾¤[$ æ-æCu—'X™xñôÇ© uù(=ÌëSe‡º]àK¬òÆtP«:›ƒL6'Xî×/¸Ë5Š3É)a‡lédšÞ‘®Jüí×PÀ—(5Æ–ª‡œÜ¢8½Œt'NÉ'vû‚`mUC˜<ÍÓûé Lf•³<öuBjt{ú¬?Á)-“Na%Ö^zöM+>a|LqîsJâsŸ"l-áªß‰+2fcÅ‘ÈÞˆóuAE2;“ iäÑpAŽS—-XÞçäLéCú!F¢KÉߺpgŠ H^wéè¤pH§`l7©Éyý¤1*`þOÛ!ôCÚ‡`äþ ê¯lª6¡8Wò%ú!¹ªL  ‰Ò7œ™4£mGF”fÅ^`¢¯`dꃽ‘µ ˬY¾—q °xQ&Ú6¨gvAZU€w1¬x.®Ó[O±zñ‘('8n{”8_6§¸]¤7‘ZìäÛ«Õ„Âm9£TÏZfÄãCq*SÚ˜¢¢Wy ð'âa7rý²%ìØè ÊaIðû2K'O‘]6_ØU~†²¬0*g³š7ŠD›ku;§ø7ü‡Q“Éë0ñèƒ8k+ÅIqÐ2êe=‰ d½Y~*¤ø£÷²ó9øøñZZ6×.Œí#\Å 3¢|a¤‡Â²T/ шKªS.oY¼-ŸÌ>ϳ¿ã«àv eL}~×DÊ„â&4®¨ÒXèÅwØÌÔ'lÃë‚­Hçwˆ•Å‹^öñ¯CÌpºÀÆÓµ‡¬§Ë CõO@mø·/‹PÊnd§’g‹€†ë>Mç€iöê&7L¼Û;¸¨nU҂ϼÕþ•÷™C¼¢>¬{öwšŸYãõbÒo=Ó›„ÿÅAèÍßð_Óé'•.ÉBE–ÿÊÍÜêeTâ Um¦4v\QÜ]íJU'¬Ï`w8ÆÓ8B×ôB1æÙ†á5‹ã#4ÖÇp€G¸ ñ(aQ£Ï1ƒÄ¸£|´×x¸Õ«²Ö9ê˜#T…©ÒÉ\ò²V× ±cT—Zêg‘¥ˆuñ1'8åoÐùâÞ ³âX‡Ø8ô7'h奯<|v6”õDÈ!³â·cD×ÌšÆ6‹çStWöSì6öÔ ™ýjjA¦ª¦Fúu·žš¸lm,¥f€»˜¹Æ©[™d0 ÄMd’Õ}¢$yÈì ì²ÑÞ?®?8öÒtzi†{ùY£bù6!bð¾NSm»·qôeñ-#wH;jWš°|fÿP Á(JªËŒœTT›e5u^+«t3³þÖzù<”ÀÄ›iŸ¼zC+Z¤W(æ,lòÐŽ‹ cä÷€š#•@ÓjS0lÁs0“JB·4yѺ˜CǦ…pµ(‚’0ö3pãëftJm9ñêâ(_$ Ed39jì‰ÐéÜ›/5ÍÃèdMvó± –"Â|CKð¤¬)ãùã|.©EP&FfêˆÔ>\¥DÆ*†¡¿ÔüyÃh\(³óïêÀE·^ˆz¯÷Âdæju­ÝüÄÑ.í÷íáΧJ¯§ÊÑ7,Xzû6_t]”˜ØyDŽÕ#¹*Q+Ìù`œˆÑË ârôjv¤žASvsãtCj7Û®Z› ^j+Õ)12À\›ƒ¸¶“ißߪWÏá§©úÒLm)ùlGL)ÉöÌVçï©@»™‚ò2éœ*Öü>ÅlÖ¦¥÷ŒKÛÉ™Ï5Ó@| q/PÅB?{CÐV¨SÕöûWÅ‚÷zÞ²à[æJ°Sq¿i¼¬{+ƒòîN‚SLÝPLÍí£=ÔÞ’Ö£{±h\Ï-­¾vÕq­V‹5€«dFЃREO£´”—ˆ¸z’øM"‘mó;ê±íjŪ¦ëLk)XòÇü‡4u[ çYk`Í?áÎÄ?;­4vì3E㢠Q…~&M…sàA¸^ômU¾X¶5ÈgM©MOB¾áÁÝBâó(àݪ‰9ûf$UçqÀÙo]:¿E($¢ÍuCâ_0ww§á}jÉ¿Vºª÷ý¡|¿—ø¿àêÑ™aDßÔÝß{•3ºa;ün7:„~Ò=võ¦iâú8òËf‚Ì ÝƒRóÃoa†ÿÿö¾®­m\kt®ó+ô¼7'IMHºÏ32m†4´ tÞöÎI ›'æ×Ÿõ!É’,hÃÌž}ðÞSÀÖ·–Ö÷ZÚvN³ ɘ藳0økðùàËŽm™]÷‹¬`a£”àßú± ýŒ¹/Ø›ÍVì¹hk›ƒ4~Ux.ûý¦@U{œ¬t ™175zµ(Ä>Ã’™Ü3ãÓ¶AÌãÄ1 ç67Šs‡Òμ¬*Y$ý¡ëy’Í‹»6çï%S>î_ÒD„ÁwMçpQ† OÀ2/8ì6!:µ–{Mé»Z¨Áz…AP¥a˵­G©¡MEò¡ñ¼¡Ö¦•B:…½ö3GË\/oë­±È"ŽœyB<-þZe‹öå’˜“‰‚­uDæ°ÏÚzÊŠY•åM¶});é¬Ê†Cr÷€"R© ÜÒÁc¶TÀNǚˆue[¦”zT›÷KgîMÛô Qì¿ÉQæGÒÊä-ÁV¯Œž,_¸_Lþqû… âO&‡ØçGí³³å=„QM-¹¨CÍÖPÌ2’YJ3×M‰EyZÝ|„p¶rÊé%›ŠL²[JqTüÅK,yt6]l˜£+sÉf+ ‹³’õѰ‚h¦NüŠ[c4à:|kß‚F„º–£ò#4h`A 86¯ý2„~—ŒºŽˆOF1 ò9Gü0NÑÛ¯ÄMØ© Íô:Åœ¡±L9ˆa>Ý¥q•Ȧ&Žä·p¤00"%|Ì@T»¥ ŠímÖy”ÌK@†UÖ^ºj.´Fù屡óÕn[Ûæ¸‹oÅn°¬¦Xý¾CUÑæ¥ÂÐ0ŸñhZ\õŠãŒ¿Ö¸IOü¿Ô…^Š+™4ÚTÒt(õu™þ¶=ý ?ëR†Xƒø[õ+žCôèÆí:ú½^ýºÕ©ÕðWN`žù\[ÛÐStõ‹¹kÿ-^R cÌþÀ^æ¬þø÷*iiù ;aÍe˜ø]ñ¼ë¬ á”Êdød’]¡ôéy2Í&8}?ß`ßô«NLv$Žyž%NÔLƒ>)×ï‚­½>õ¬_ŒˆÙo3_™æg:3åY¾ƒù”pBßÔ,µ¯" vú„51*U_b«š.ã(Á\(Ú=“ζ‘&¹Gºã³÷#1*Íçll1xB~$ˆÁÓŒ&^$ˆáK™“®PU^´œÇP!à]¾9-IÿާclfÊ__>è–"‘Ú£P« mÇÖ0Ó¢ZîíæÂ1]9×Ög*½aqÀ«DÛ?u¸Îge~Ê¿ûçÝ»_Ä}ß8\‹¢/²`ý0LãGD # œ‡wxK²Îü K%{¯¸åŠ‹õ¨±SüiÎÛ$š¥ f¥·ŽÇ]‹Ø³–ÊæC\‡cÄyvn—ÛQ°g6:ÿx<Ò~#ò:š­­x ±ÚºU¢îA$8¦Ë“BŒÍ²q†ä‹í’%jlØþ8}„S (÷eö]&¹Õ{0 ™N³àj7°Ì€ºÆˆ3rÌØ,`8D÷“(šfèèÕ¬WWI¼D60™¦Tý·˜òsªŽš ª¤kÇ8`£ÒÒµyg"½ žs*ï7dÛ‡x¡I³Ñl¶Ž›uY‰„§/ä¨f93F+Zúw|p*ÁîI ŠCÉá:¶AîNúcî³î=ùï["¸|¨+©f*yƒUêèž´ãzüé È¢2¨¯yìºß…ü}•Ñ¡Ð(ª¨nÍÝ;̤W…zÏìf>Xü’»èwÖvH¦ÓÎù½ßOKE9¬¶YQnS'£ìŽoK˜“®‰(z¹©*È\š°H «y¸›§×îR‘Þ2¥ ¿‡ñ m•ÿ²YbôÈ1="C 8QvUž&£Ú®É„½ §ÀHUÌø.¡vé[Ô ¼£$‰Ò6®‡®Æ›¯FezÞž$v{Oy?d :ûGÞ¨OÎì…Fœë÷è<©LÎòÃðAУœ:B·-Ù7C¥ÒK›«ÅüYÚb‡¬õ à™íeP\.;¤µ-þ*£T¾ƒpé9l_¶~t0Wœ)“ Ç2L¹%ÚVwf¡B—EÀÒºýRåš–Ùôe5x–@Ë[ L“R9¥7CÞœ=râ¾Ì€g:pL©P¤!^©ã?×;hU–áqÅ>³«‡òº@/7õ N‚tÐ&Ö0ž|¤`|–? Ç¢]/; °͈ÛÉ•;$2i{Uzwá<Ø€OÁWb-˜6… EfV̳ڿŠrÉê ê6¡lH¬RˆËû[JàBkµd4'ò…ú–Wv@– Ó¬—4 /² èf¿G‚ÕiüÓJœú³$rm6<›¨†å”‰Ž¥ê÷Ÿ:Gú®ÙOtÉù!@z”4¼c3E6e1GÄ \ÎðaüÒ²7`¥ÓA·æµ™h;¯¢û9Ñ/•~ ]«œ¹ù³Ê¥qò£é’–¥ 5Ž@z. þåÎÚójOB™ä›ØRÌàþfó9Ìhã in¬+ !6µ= ~OU.Cã Z׳¾U¹Â8!7ýÛGÿä¿4¯ZåG a'¹ö cí3üúJ×±R²*«BÇÈ裔Üùs²Õ*`G7 CZlFlåaIú¦ŒaÇ™ºÁw7S¯þŽiß‹g¸êÜ/mþò¦Uü&ƒ Ü×28áM!;€¯GuèØûú™Ù z"O(„nþ\¨•Gä·w¿äræÙî—ëªïµõF1ô>ÓJáz»ë$WéÄ] ¹Fx|/¸sð•Ín,üµ|-ÍÀxs1›ž÷Ü̽ÞY?!”ž{LD´´Ì¸ë6MÉs[Û…½áË!8( %0úõÍYýÌ[°}k†¼»vÈr íí3Põ2=2ëaom_©Ÿ & oßPHÀÈz/‰t9ÓjÛ”w]b¨, ¸ÉÉKxÙs:7_6r8Ð2ŠJ"R|%´€!^ÚÅYÍ‹"pñÈÊþ"åN§#W=Ëà±Q5Î~Ñy@ˆ}@ˆ}“97L¤nhL%>äßÔ0x†òÆqdb`w‰×O\¼®qÕÀPyJ<Öx[ÀâüÍ •€½jÑÅÙòZô—ÒRä¢Ìu9ñ,^¶Hé fè(ïlò©Wd›Òû‚Pâ®JUH;- ^p¢0Á~|™Ö6¯ò¶9¹{ƒ|ŸäÞ Ì½+¥.­VÓÚ^›°IЬ…D‰î«ò¨ñÖQ–ÁЉÇÈF`˜òûèÃã”!§ &ìN’éþÀà]ÒP$ ¼EÞsÁ„€>{ÁÀÁükT—(ƒ<žÊT—Íf«.×i,û£œó ¾ñ¤@ÿ\Ð%¡U¤Gÿøj¦I]\ē،R>{b8ìÐE~ÍØaÙÀp:þ¹÷ƒA딇‡FεÏt¡ä?NÏÃ>kÜ*Ýyu=ëw«eZžÏ¬ß9$õÎÓ5;z#>â};ÈQ[ÄPB‚¸ñ¹~héØg¼¨¶ÚÃ|/É`‘¡ÄG²ŠŸmiKò‹Ÿ]Ÿ˜˜ÃªOX>DaÙ~X]+Wq¢Z íð˜Z‘„oxÒM«žÅ)ôäл:$NÀôa('‡¾qâmŸ.™ŒÂ¤MCë Þ‚ [Ý©¶È®…У2§(ɸD@\Ë&ôGÏ8!Ü.² ¿l晆ÙÍb{:‹“Û›ÆÅ†už&̓íÖîöþPë=™EÀ&Í1yY€FÅ—=jÏyt# —i˜Ñ'lÚ ÙvÕc¾ž u«„}Iu‰ñ,Ì`÷·Á´ƒxÎÃ{ýeAa 2{VåPûÒ!#ÜTp”ܶ‚YÌ[ذlÚ‡ÿaßb–5¼%FZu—¾¹JÚC?LC={YÅ·” xÓË1Ä~S5ý7Ì^âhôöÁ ®‘½6ÎËl+ €_ó#ÝëÑà–Â'žf5ÙºyÓ B:1ê7¶U“èé “™ÙB¦j~Žh/cøêN•Ò-Çxå§9œ3Ðaó$N›jê»M³/µ¡=/‰êÅÌe£3nïFµÕr­Rb “á®Ý/r@øùÆûù†?/-;¢Ê*éŒYeª´(ƒÕäR*4§ÍmO‡”„Àw)Xâ.Á^Ñ>9]¡Õ¥r+h÷Mpä€j§)®|n¬Ê麰 ¾EnY®æµZÍb;rA¯õ‚¶4mzM¼(xò ‹"½VWÂïöG·Âƒ6 ˆÞþäÁ½Émf18“æŸûM·:: N/1zXM‚ÄzÙ*%ùþ#J¦ò7›#Îf6G<®Óñz– <ÆãªÍq2t”…z|½ž,Šº¸‡yŒ12 ™ˆ0ɪaM½•¥Ök*™v)6õ%˜TScYÖ›øOæTÅÓx,r!-Y¬Çf<.[βÖË‚F›rëgLœ›j3•jÖŽ_yÍ®UAÁš¬WÆ[3Pà©REÑ ts}D(Pë´ô(4ÒóÚœN3Œ6è"“—I#M‡X¿t2Y-MpETVk…zèay¨Ê0„Ül4¹Jâ ÉŸÌÙJ–339c¨‰ 2ÄßHtâ£'ëA·Ê¯Ûæí™&á0m”Lc þ´O’ž‚]šrÔ¢£†-¹L‘!* 4úÖhÕ±K &U"ƒM£çV³È¦ü§söÓtùC=V \¶Ø«±fæù“ŸG”ÕH"Ên ù¥!Ö 4²rœ2ï™ü>«?ðW›ù-2ü¦+×y*/Ï/$ÿÎ|yŸWgö˧ñÄXj¹ÞquÏk–\ÇœñWÅšµ ÌÔŽýÆ$šZû.V„Þ-¦ŠÂ‚¸Ë…²†sC»Ëº÷›±õIÎ øXobÌ kaLïf«EÓÓ“ÓSó²“jÕ›’“ôÍ“áJ·À%lÀ[ÕŠ f …YâY¡Ùøæâ.W•~n‰¥¹hoŸ°s<¼Y­¸þ“ðÎ> Æ;GáFžàòý I"D–Á£~ÊN–ïí{ËÂùO>\û¾ÃuP€§wîtrî)"Ä•êã©$óY0_=¦\Ï =ªbO‹Jöñz%û˜©´¦½DÁ>.W°_LÁ¾N O½KP.…X¾r¾±œ>f² /£†0œÇ<šD[< xj˨ˆåx€xƒ¹—‰W|£›‘Òns‘ÞyF1Ÿ½iéßvþœ¯àêÔ£„Í¢HŽoÎìä8š– »D‹2Ë^@óÛV).¸â8@󑌟ܔ“ˆv 1ZƒnÖ·–gîÈw‡Š7u¼ŠÝ/Önò…‚Ð !ÕÄž Lïù‡ãô{ô¬ÎWFçnr×ÐN.tìh°²ÞZƒŒQúvúE"RJîÈc˜EÊâoU†™R%Á[ªFó*|!œz™FÓà)ÿÓµ0–}•¾ÂÞ¡@G§&À±»«ì$ˆ›Áup½ ®ÿ ®á×–6ÄÎæüo® ²réT Z•6W54FÙòZLüµ'9-k]c¾ jGù ^·òC?¯¹ª")·^7 *‰|þ„Ú0 hÆy©©—¸þÓ’tÚ€*ó™%+"€sÿ§¼fÚÌÕ1¦ì×nºjG2ä!©á\¯¬EúãöS­Ù-siZ%º­{6í]Ý/3 <¯?mOSÚ¤?Y]œÔ,³_^@1Ê-_¡TL1×Ù•²Ùõ‰ò{¥š’G ös… '[¦Á°åÏæhʇá̵1^jÌ—–þùæú(ùûÍú¨ûY»þ\5öÖo×—½ûvIÙöå ùŠÌ ûþÛÚ÷}~ÀmK޻͙øép3Ô (ÈžZØc™ˆVýZ rp2}Ê9¡ôsÚ‘àzå®ëŒÀͽÎNw9÷}Ê·r­ÿÁ|^®ŒB· 6}^â… ¾qâIŽ…½ã?æ¦3Â!¼{ÌCÃïdøãc. ­5hÙÔ U¤%. ¬?ï¤0FÔOøÆYÁV1®sYÐF×iaüˆÓKN›÷\+ËúøQÏ…gë ‹ž þÞÄf•fÿØ‹©·6ãrQºUÿE.Á«ÏÅ“ÏÅø©>ã¿ÕçbŒ>> óWù^”’¸ÿ& z«¥þø×¹eÌÂ`6fßôИ+qœ|Å%þ5~%nsÉzE~ñ¿ñˆk‡X+ìÉ%FjQn~šˆXkª%® â™dGˆÓÔßéâ“×ò¹±•AòsHŠ-(g¿“R£ðþQ/½fp<ä’ÍÆÿ@G“X7ré€õ)[wSM×ckÞy¥€Þ=мt™ƒ‹(õqO@?¹hþch5^Žfžæ#Êñ‘x¦)Ç×ÈÔ?íÃNlPõé}'“û`ú€?rAÍ–a¢’ý„н­ò¿é&ëÊ*Y¤ÄpÍÒô– új³,¿l6M´uôX€ä¥²@1 ØÙnµ€1h¬!¶÷(>Oèß°¨jÇát‚~> ^ý¶ä Õø¢š A¾Y³Ö ÷yMC-à|¯bËø½Õæ¢]Ð_5'bœ±I:å˜ÔU³7–ÞºïL yÜüzÞ|ÜxF5Wð`þ!‡'±Y£bÕ­¿ŽoMÕ{å¬rF¹\Y릆 ? àÊ_àÌ…uØ‹ø>rê<Æ>±ëü5ö?ðëIaý€ë[ÂqjÞ”—Ù‹cVÉ?ÙZÝ òºí%<’NâwkùBÀkÉÍYzú;júskújöÆäU8Ž«|‚ƻ„$ ms²Ìíßã TƒÝ'õª `Kªÿ® ÒŸná¶Q¸mn ï…wìÂ;5—[[ÉøqÐ$%”I”Ðml ž@ …?5þ~(Ç>Y)úiý<òÉùdˆ|6‡yþ?Ç,™Â,Ù? ›ìÿ 6Éä¹Îž„BöŸBöË»ÒoÞÈ ˆ"3EVÀ ™2˜_w¯»…¯{Æ×½Â×·Æ×·?Žd8¾Ô`trüB×_Œ Þ| ¹ž§26›ækpœ¥xE"“ ¡³ð ”²‰ä“)AÔréuãZçX¡½ü„‰B²aP«gQÏ?ótîý­÷ŒíÝ{þÝ[Û›þ i»—žßôÜKÃï îÐm³À®]`÷yg®ÉJï&£Êå ¾-ŹوŒ,w©ºRë?BÌXFóÛgÓ{œ½é9¯°!çÝ+[P"pȵâŸoËu?6Á$Èý17÷/à~3yÖ„—äiHÊô/y.š*ïZþEÈ©nH!\·. LU·ä…ê–€¡zëEGo›köÿx†Jó¶€5  ß@0— —NôüœD÷˲…Äb²ZÎRúqâ*^FxõA¶šƒ ƒ.€¤™¥ —hÒf}%¼Û„Á¾5¹ño5™ÅS€,}ËåÛÞ’üKÎè±}I;PËÙ(’J‡TáGô§!h^ëÇõQ¶š1Ë 'PÒ¢Kò¸)+ÒÄrnÃÓИ5fá]†î³­wû€Ñ<0(Àj!n¯Â,óhy•²ó€tG"0^ų%»Å1s¦n2Ò¶¾«ô6ºXQÊÒÛÛYdË< .žgx¡%—Úv>M'dWg?Ü7`D­rÀß¹x«½/¹ì6Ȩ!xÂrŒné4c·ow$œ¶;Í݃¨õÎ^§©gÞîó2éNŸÖg>ÕÙéA£½Ó:hM·Z-{²²× `÷箆-‡:ÕC%¢b"±MM·±á@p(.¶×TÀ…oᲫ UÏîÁ`s¥§…ÏLË„fC‰áôkefnr;ÀÄ…Y_&Èê,S“$‰µk' Ô:3†kw¼Ï8ºŒv›"VNNCñÁlÖåñá0‚êí=øoÉw«©82dÁ¦á8«ÇT3БZ‡Åeɹí¹sCÎAMΧDĺ ^Œ8SqO4’5‰çÄoyŽ+Cy|°k† ‡²ˆðª]:¹7ìIT0ñƒíï²,‡61Ü£k»7ô õÁKl 9[ù 5³§VÝX{¤­²‘ª ë} úìGùC:)â\¾§1¢l¹q©¹&ãR^Ý_UšÍß/_I RÆÐN%ÜЈ3 Àˆ¸vËF 'A‘L91b…±+æAnIË3\$ä´À5c9óµ ÍA~ø ý^U*¬vŠîÓUOé>é­jKü}Ȧñß7‚‹ocF“fïoGmÌž WuZMþ4ZÊÄ9 Ÿârt1cYê2בe%C!צX¶ œGGp°ç~„—(º~÷z:r \çñtk ä isé*¹\W"Þí¡ûX$‰©úƒ]V»pM0 -ðhj¶ÿT×»Ì[AUò=`rð«dª©Œ}úIhmàfd+к ïê€.¹ý KR#rµï{"C•Ïßh!)…îNE8½^qšyÏšÉ °Öå¼`Z8«'Ûñ•LªåW•벨âÆÀ›L:~NvðNOŽDWœ*6l:FvìòO«ÍÞí!+}Ù½i£Ñ‹<(ë––k}W[fAR†½”âÛRMmÓÒ(Æ«~ÊõYmCŸežŽø¾VC`œ~>}FI5ÝØ`,w/ǰçÆ&ô킸œÒ¹ç*ªÒigiù>ašµÅVá€üݹݟòpþÿ~ï¨;u_¨õùÿ›{»ûyþÿ6¾oíìïì¾æÿÿ+ž£ôö㪓’®v@—Ç Cwâœ[þÏG@Ià&qØ•Od#‰¦B^¯í¿-†}£ûá8]„Ëtñ *Èìc¼˜ü¨!>Q˜‡‹ì*ŸbÐP·Ï ë7İ—Òü™Î¦Êqgt2ü—8?ö·ŽN»[8î­æÞA¥’.M'Cea´øŽ©!*•a4wÇ«<áG†dHdéj1á0óqœ„ ¾€. XáˆH^_[™æ¤¹À"8…)š‰0YÅ4¿c<Ïû £#² VšGËU* ÙC¢…–c!H*ÌEDYQ(Rˆ¢f&j·*@"âI°';êa°¼/):™ÌÂxäŽ"z•J»Ø9¦qÉg¯:gëW´©þ«!¥ÁÀ I­"§¦TD:Ë6f@/”n%ZÄ5¤—˜ö3˜3€Y³8ˆbªEzhÔK(à=Úî÷}ÔSëo´àñ2#$Nͤ‹¬2èŽM™•8¼Åà*ìcWA¼Ayð=UZ2©Ò‹å*ŸÔÇÙ-° 3P)FH’Op“e<ì³½‘þvöGgØðû§áé—Þq÷X~gºâèôÓ×aïý‡3ñá´ÜŽDgpLÍ {‡çg§ÃQå:#¨ù?ô¡3ø*ºÿûiØÄéPô>~ê÷ 1h}Øœõº#¼û¨~ܼ4 §g•~ïcï ŠÔi±Þ[ó±;<úv{ýÞÙWêï·ÞÙúªüuħÎð¬wtÞï ŧóá§ÓQWà´Ž{££~§÷±{Ü€Þ¡GÑýÒœ‰Ñ¼`:¬ »ïáõ‚ýŸz_`ªØ ¼9êô{Ðþ ×áÑ7F qÜÅÎ>b3P¤;èß­À Ì•‡]ÑïuðÒ&¬ÍqoØ=:ÃEÈ;‚õ†YõƒÊèS÷¨¿Àva :ïà6GÝÏçP>ŠãÎÇÎ{X‘ê# ;yt>ìª!ŽÎGg½³ó³®xzzLÛ3ê¿éý_Ñ?ÑìÏGÝðÛY‡:†&`á3ü~x>Â{±FtGÕpxN7èÕ*þ€Å„1v ê1í ^q5ø  Õ=ÒâЖâ]x?Äm •êàŒ`ÅŽÎÌbÐ,àY%Ÿ£tß÷{°KG]üzŠ­üÑuk°Ã½èQ·3Ðçù™ÞÊQ·B¿pÐþã]‹ã/=¶, 3êIè¢%;ú —ŽJGf=:r8:Â@ÿ=I€`é^AFS(A.€Ä+Ïå…)Ÿ"C Í‡0A8YŠ©â @CÉzI¬( Œn-.Dõø´[“}Ü¥‹qf7hJX)#še7ª¹4²Âc;R㤠ñÇÖþnso«;x¿µ{ ‘¡€á0f7q ôØv´¤È¸÷¨I¤|±(RõJ>@*&Æ ´Ÿ>DÆyxCÁL0gÅ’åC ¢{·²¬Â±s³8šˆ4à ÄIY30Å3ê 5 Ù-P‰X¾áÜQQ%Ä8ºp NäM± ´JMJ¾XÍðO2ð@ƒÿ¶˜+z|‹f‰å* *CkcަBi&‡…” ˜m¹C2€ìÀ]ºšMd€2]`:“ø;¬Þìa xXKæ-˜ÜtfYäYfÚb¤¥4<ü)ûÞbBù<$ñ ANÔÔM¡œbxAñ"œ2 øwàˆnpÍ“†I®«‹ QÇ»8‹(µ–ÌžÈÙbLÓˆ–Éx‰2´Ü‘š¤¤gAeq^À©\BŒ  ¿§”H^•\ @r¿Ê¹Bd!¿ÇÑ3émœ(&'\q\d d¢iE®Ènî<²eÈS€EžE¯Ïëóú¼>¯Ïëóú¼>¯Ïëóú¼>¯Ïëóú¼>¯Ïëóú¼>¯OÙóÿÆêAs°odepkg/src/hairer.diff0000644000176000010400000000000010744431046016072 0ustar marcoAdministratorsodepkg/src/hairer.tgz0000644000176000010400000020152110744430734016004 0ustar marcoAdministrators‹¿1’GìýÙ–9² ŠÖëÑWøÕC‹ƒ“á#U2w3HgÐ#Hg$)B½zÝ¥TFeª[)UKÊ]»ÎÃù‰s?øÚÀ8œdL’²J̃Çh0Øì·×o?Þ|<ùËc~øô“„ÿöRã¯øü%ÄIôÒÞ_‚þ†ñÒGí•øüñéóëž÷—ío~ý©>ß¡÷r òïŸäóÏÿ/oþ¿¿Ü¼ùôá]÷oߣW7ÿa/‰‚æ?íEaõ{}˜ÿ4ìñ¾ÿÍçⵎþ<™xøy‘­7ùªðV3o“]n³åi¶öÂï…ÃaJ9¼'·«ö —ÚìN׫Ý6/2ošMVËu£ðgç㉿˜â÷l9ÞÀOü^.è{‡ß\ø¿yÚgúËÈ/àÏl< ý,„bð•_¿líçç«S2^̳ ¤ÁwSt _^.òI¾õÖÙxÑxqgî¯:¯äûi¾Ì ;v«ÁÝ*šÔ³÷ mBƒ j*ýƒn4è µÝ(dí‹ÕY½ò¸g"À°\'‹¼/N–‹  ÿN±áåé©¿œæã3üžÍà4ÏVÛ•×ýÈýÄOýžß÷ÓTü†~ùa쇉¦MßC˜@щ׹û‡›±ÓÌâ.ãê<ït”O3HÚ^ûô|uš oìÍv‹…·o×ù•ðÊ;Üž(`AŠ—›IðçþysÔ¡yÀŸå묘B©'zÞsÌ+þ¶%ž8²Øˆw`Í^‰1²öu¶Ý­‹Sx'0ù°â ÔÔ[­§ÙÚÚ2,}¾ Gçm=råv.$1ïËIÀr9Z†'ËÈì¡z®ïÎf·Ýi`$BÞ‹Qà/—3³È߀¯¶ì~û¢µŒšÍ­gî¡hc;POÍÐëe~Tñ¢£Qåt\L³ék aOT¤6™ã— ¢ü}p‰êkLµG\kwàýWÛ‘ >´æŽrÒ»ÅÚ«v> í÷mW᩹ ›¼ØM^¾©bÏíYÝý8U°_Ó?ïpÔô—yk %¦¦³jñ—ªE¢LÞ§ÑnI¿ï¼ç |m.Z;O€Ç=S$&éì„äóð…Y”ªèÔ¨&úß&±¹Rû©„ô©ê[®…/Íäî=ß»ûòÆK¢÷0K"­ƒ=$kPƒmáØ.НI¸ïÇ#Û5¬ÇÓÇ#©½[CÈ$¨¢ÌveV—[´UÀ¯bµõ.׫ óNA"êßM—g›MVœfë³wUšaf^ƒ MFÐl±„O\|˜I6 ±õÆ+‘GÝÙx±Éº‚èÒë9â‡öŒêlX’(úíšéÚ…yþŬsm¡>æRMõ¥jÔ®:GíÈŽ¢1Ð6ßQ†ãí€Ç'÷7 Ž—óÂ?ͶãÂÏ¢5üË¥‘0RF‡¶ Vz-k–Bèƒö!3¡D€ï†@ øÕ.5zŸó{S«­,B¨†W¡øÑ&ôxbÔCaö­O“ ¬õ¯lC¬Ì‚Á9¿Ø< éѲ~ŒO‹Õˆ*iµ¢6•‚òåâ’ß`6‘y¸v=ñVÌuÕ†©ùm-+›Öe™VùÖ˜oÓ‚´±™tÞ‘+ÑKÈÕ¡ìv.—FN«ü%×îy•?0K~ÁÓ°¢>úŠùr¦ÔHôˆTŸ*L÷¨¯¦"ËáåRšµײQ’°Ó* +Õ×G£eß’'i¿Ö*ç©ýˆ¥?´Ý¯jî}t‚ç´ÿ«¼#V­ö»†ªŒ¹žñVTñÔE>œiûÈmÜߎQÐŽ·‰ŸžŽöÙU=Wä5ܲìUªë¼õ·G0Å/(C~{¶ô‡’&omfŸÁÔßuú±ì~ÑHc3ã¿®¡þK@Ú Óü¶£Î9Ï1©Ä”ÂTf5¶dµös~ª&ýtÿ¢?½ëªÿ:r×·¹mðÐØív4Bp<.¸)À©"§w¥¾‰ý+‰ÖÇi‹ vˆñC>]òÝ ­¯Á=¿µ _’r³R˜·ß7û¾ïñ`ûGmU e¬f¯BÌ'¿Öèáö0Ü2–ŽcGmo<œeu^Y×á#®ìØÿ˜<ÆþÇfñb=¶£— úÞÝf/¤ÆEú<‹m¥Kr~¤[zHC¿ð{–ÞÒ¾cû!›ˆäÍ}wføÝÚ»u¸Y-ô=þW4ÉßüžÄ]Æœ ¼ÊÒ=ì¹Ù5iÙªÐRå¾e®:¿XŽØ¶DûEÚ/´{ñu¹Ú‘fÉû dÝIÕÉÏ»5žÚî}¦î7‡ZtíPuzv`ÿ5öf¾¢þó5DÀÇÚ:v’özþÌà—e%_d/ê_Š‘TíûÙÅŸ”K|ßi{ô¶¯¾,¾Öî]dïE¼;dÂBŽËxÕJb»’˜+‰­Jâ{ofa0ÑvÏÌ×Úu(k«2@Ϙ™ËÁQ;ˆ×û ƒxœ­ÄãÁÐ> í£ÀàÝs'òëáÚŸo;3´íÌ郓0ö4Ck[³~gJë››áØàÜÀbÿ½Sêð…Ø­·Že;¥¡{¿ôûèQlwŸŒ÷øj@½+Ú¿ï.ê—Ÿ’Úeµíq[à°;þ7½wðx§q¼on7wïi#çÛ÷µ]æ•+ä¿ï ?ÊÞðWf7Gøßfþ:Óô0ÛÐßYÐÞ¾ž·9§dcPê8þ%2f\"ã½w·?÷ï²!^9ñuv¦èÐÚÃʾÆlyÔž¢ñ¾ Eèßxóý+‰ w=3tÌâ8O­µ¡½‹à]íÖ=-+(îC6“WÝqC__U•­šÚÇÙ{øÉûîpÇ£šßÉðWTþ•|îŽYÇ{%üë¢Í·Æ½¿%‡AÞý0ÿl÷»Å·â_ñõ–áŸéô´]Ç¿˜‡†Â-Á’ç}aO}gÅÿî šÔqD¿%§‘?÷ùó9žLÃñ$ÛlÄñdîO§!ü‹à_ìÏ&…_à×uà_“¿ˆå—¾)•ÒÚuž¼0Éó„ýPÊË=7° ýl½vx¬äëÍÖ_gçÙdËž/ëËñŠÕ]«ÊQeºÚ.2àÙÙ$'Ç”qYQ^(zß°ÃèXr¤ÿÉu@ß®Cû|‰ÃjPsôWä[¬ÎrhʃT níÇ"æ3ËÂLéɼLˆ !ÒbHˆUÂâ¶yÇ•#¥œRD`™F£ $ÐŒp -&®ØûSPìwË¢ ^(AåÚ0êåA}MúH©¨ŽL0û5þ GKp{öãw èÍñÐ#ò~5.¢ä<Üm£<$T-Ô/+"ÏÃ_:J-•»9ž>A ó†øÑæÒû¯Õ±¨ºÛ¾‹öÙ¿ÜqZÂÔZq-•»òk.–j¿/½Xh'¶~é³· jvI­•õÈ «²MÕy°=OÒ’E6§éÉÀŸ*úÜêŽE¨þµoË"¯([;Vø€¬òþsq¬åñ‘HŸ@Òö£ao<j¯6Ý û/!¬™°:0D$ÀÊZkì{žcãë88nïëûr¼#[~ˆYù¾0ÿœ 3­Ù3ì<жáX”•«q (S p/˜¿3À³\kí˜ç¯ÈÝ*»OÇ,"ÇTç–{PžcéÁ¶‘_Ÿ¬ÛªØå¦ìª%;5Üaû1k —vßЄ,:Yíµ°"Cm*ÙÜe©Ý5ˆ¿åu¹°Ùªvå°"enؼܹ«QÞ±½mߦ·ÇOJ’<ä¤@m®I};Þ˜O‹§ß¯V´6ÂGO«¡‚1ükKÅô„ Á •–îèæ¼B~6?­· x8)š~Øv ©lö5xÕ]l»ð*hšÛø–¬¿ÝÕºËà&P‰Lg~Už©ïZ)ÐÆ¦IeˈÐn6AÙöJ™é+ÖvüàÀ¿Ú•½²Ú^Ìøæè@'ØÔ‡~ùÆw\Zœ“ÐO"õ­,Î’þitÎS´-ËîX»¦r¹ícçªkƒÁ¾†l6Ô¶ê°%yNs’·×¢äÝÆ¨ä¹9¯úÔ<3oŠõÓ{Àžäé³qØ*ë)ÉÄv"8Þ„äèBe¢ f­p*ŽÊ–Ìɽ•NvlƒܪmþkâÖ-m–Þ±îË¥cfIuøw++¦÷8ˆXEŒRl«R¸¸l¯êâöµñ\n^÷€çâðih"T-—W°przR‚Û§B«”·G¸Ñk;RÃOþnyP4}s8x5¿ÍH‰jÎŽ{·šÔ^òX“ÚKöNªåŽä°Ø`P[“å'‡\MŠ_޲Êãä•bgîhò7¢é^òªƒ…ªfüwCÉtÚÀ_ܯäk;‰”+ÓiJºÀ<[""C@ì¢ÙçíÆÒÔbâ 3· ²)ÿOSsøõ·ìiò§×w•I•? þéPÿ¼^þ4€ûî;ã†é¿¡ïÌÇYc¿æ~ÿlÿîc¹¾ªs÷§qÀ©žýûVi’B{ó[ÀÈ/èp0»Ã^é _ ²~]_ ïäeO_ïG^¾-‡¢ï„æ;¡ùF|›¾…y<8‹GxG};òÉãùG}'_Šlå¨õµ…5W­?E@tå»Ã×w‡¯ÛLÊw‡¯/ìð5{@‡¯aS…}Ýx$—¯z¯£Õ³ï__Èãë¨ OIIìióØ>_ß¾¾;}¹»ûÝéK{õÝéë»Ó—!É)Ÿ¯?™Ó׸iè·¯ãjõð1®2\m°Äüéµ?¾ðgWþu‘½ôçSvÛlÇg™Z~朅¾Y5ÁªòKvÕš¢ãt‰.ø¹"O,èXéŒ%½«¸‡RÉ»sÜ)\ªó)®Õ€ÔSp(-ž}ƒå7½6V¦©¨,6¶Žk/­’ö|Ú‚‘Öׯ8_)KIòßn¨,³À©*ˆë CßmšþCÀh`*€ä€Ú¹"¯ßfȪG š:Êeä!"tŒÐ7VãA\¿p¬(²Š¿v¨¤ã…Ñý._„-JÝï“ÐàYÀRû=@¾B_vž– QåG[Âçñ¡t´×[’äÔå^¬V”šX¶§úº-‘ëÛ_¿-¦Cݶx(G Âö};úÒ('ý›ààlå á°Ìñ”ëåœÕ öîàmpÔD›û‹Ž.z5„Á¦ Æú¯Ç†?aüú…ùý—mY~A†þ 17î;‡==þÌðáV|[ôÏ©eÔMá—¦mÎ õ ª%G-ª^«……¿÷ÏJ“r%6®”0>–2°ÿ¦n(_Q†G1n²ÝãùÐç4[}~ýÑóþ²ýíÃï¯?Õç;ôž¨¿’/TmUN³ [^ú”ïA›¹„Ùº ëøE¶& 58ÏŽû$Õ¼b›ek¯ð©T³5)‰þÅ%È>>ÈÊZ[¡£Æ¾¼§ÔæÆ ª¨@Åêµ¹É=È–IÂ<éÙ_ãâl·¯óWc2rœ^{gãÝfƒ‚^¶ÈAR¢ô.Ê‹ËݶÛ„­ðF,ò!yãúÔ+è8¼BÍ (–ƒ‚¬ãõz|í)s!«ìÏÊ;ÍŒ^eSÊ“¤·=&‹¦»ÈºçP~wy ) z çlWkßÛyÕ2g[*³Ü-¶9èæ0¹ð´X½t×{o!+™¸€:.Лƒ |…£ºèlçÞeþbzþ꥖½hB¶ºÑµÅnyÊðBlYOæÐV¶i½•ê'ôJÈ/TÆlzr×|,pf«°‚š(-ðZäôÆ[v ‚c†Ý&óH£Â2«Óí8/ðq·s³€•¥6×›m¶¤Ó :ºlŒq4šÖ$éÿD~Ôlu»]ø Hßd™q®ÑÊçn—}Æf_æ ÈLs´Ÿ!¦½ÊÖ«.sÊu6ËÖY1ÉÔOºÞi×[®°Œ¼ñâlµÎ·ó¥—D±/û™ý´c¬…ºaúªä¸;é.»hÏm„Ã~3vÙõ¢~Ò}¸Eäé“%ŸÄtKñ EžÂC™Ç QæA¨÷ef µì K!®ÀÄB†ú äÒ.¼¶W¦áúºPOPDÓÓ.M =va:>Ý4ý/šM±ß)KLiR]¹Ò_xKX+F¥lá‰Ë?Ñ[Zò`/ä`£@¯ƒ`Óab&“¹ªíB¯!cT×-hqË-²«7:Œnâ¡—“­ªØU¨&sn²Ã¿ZF¡4ðÎð•€0¢*s‚”õæ‚ßl­9rŒCmë‰$F·5'W¦lÔýh{åЭ‚žŒX©%õl÷11Q?'Äë|À¥<ÀÒ¼4.¬¥ae­[ޱô¡å(o‡é—í%w?E®zwÞnòõ‹SÿbY®â s?ÝÏÞOÃäk);@ u“qêUùz=[¿WG¦nòquš€Ø<ÏÖ«%Ö&JœB‰u~6ßzÀ§À8€G¼È‹ ù%ä`Ëé5UÁRÁ}äu€µˆ6ó10¢lK(Ù-2ÄÞªPí+ˆq¾wå=<Ëp0…t/SˆnÈVð´±,ðÒ.ô´ “$U؉:&q J7ÏM2ã&ÑL´.N«Wü8-±=x¡Ht ÿœX‡Ö1ÆQ’ö×c|¨Û³ÑÆÓFȹCl¥;-¤;‡‰ÖøŸLŠ77©Öâôqô*.ÆZí„fcÔêx B£íÑjý2ŸâóéQêŒ7~<…>‹S¥v”]£‘4pnUÀ¤Š=ç ÈùÛlŠÐ=˺aó»RôðJÑüÏ ‘Cù1lÄ,—«i>Ë'r|Wžn­<´^ó"@ëúiÛd(:«·Ð«þ-µªñŸT­ÿ{êUóZå½Ê!¢<‚ruHBù“«XJÔx,%k.ŠÔ ®…Í¿«a·TÃnؾkhô¹“†v$ùãß&å4öŒPÔÊ Údµ¼\€L\G¸Þjo©$ë’þóoI_Ã2bB ñuÔD‚ŠêœdOoèw 6@>A|çJÍhð6ï°#µ¾…öõWfˆ—ãõV•ÏoU>_ŽÏ˜ëk³’õC¨s·üìÊ—ë… ÿ"šéñŠé÷ý·ovÿmÍŠb›ŸrMmä욃¹,°4 ÜY«D‰ÚÊD쬨ô¾ÊæZi›kKÝÌÕ›Üz³VšèZÏ.óýú)d»°Ùæû”'´Ö£íºµ]··y «V€ä“©v(g›:ÛÜHªìªÏåz5]ļBí1©zœ+©Wë¶* ç‰£Uª¿Èµ¹&0Uà²G™V`(Í% ˜ºôZ©Ù늞«wyåÝZ)áÖdrîZûg1Ø }®g².*tl“j{¾*/õi2^ ¾Ê ¦{¢ßcàh¹rèà¼fÊ1Xó^9úõÁѧ{GïÆQ5|j>ÄðS•ëÎÃDZõœÙ£<°bÀ}Ç€“A%éÎ&#É!ÐpTrzúŠv¤ú ú#ìH.Uêþžæ¶5éÁµ©}»ùÕ©Ó5Ù–NóoÜÄt´I׌D!Ô‹X-ºÝž~&ð”Ê}Íý²ÿz†%\ÀKK²lÔ­MkanZö¦\¤æFêºaËe”ÁdàõïCJEЗ\ô;wÑ`èX.FkÔ7¬RÕDz~¡h)dÙ–øÛblË–y2_•—@ëÌ™Ä;ÎÙ嬜”:¢š ©•ÊRº);tL< „é˜XP1Ô}KóëÝfB—”ÌÆ›µü'ŒŸsÝ”¨M˜–ºR““&¬ÌÙ嬜”êž°°:aw2gÃ…=Ï͇ÑNïbÄ5Ž'ßíšßíšßíš_Þ®yŒëæ7ÔTŽCß £ß £˨€C¬)V,£m6-Ï™ÞÓõæ»Iõ_Á¤ªÏíw›ê7oS/ÿ팪®áÿËXU÷Ïíw³êWrÏ«ÕèŽ0«Öªsßm«ÿ¶ÕCÿζW§IÿàˬS¶þ&ŒxÇi£ÔJ#ünµýnµý³ÚÃäÉjËO¦„pjúà/ðo§Yle¿ˆgÿIŽóñ%s‡Žò-ÄMÙ¨¨%ï\fUþ(Þ ¢><äh_[¸üêíóÄ/ü•¸ ÌsCu‹*ó‚:æm€ëÏ€Ozôvüp 9½ªaPôMviQYèT¥…|Øò¸˜VëÀ|Ò¸Ù[ãzõrãèÄrÑ¡`ÙÙÜ‹Zð¸ÜA µ)‡ ЧϭN16Ué—¶'ïˆÒ¶•Zôð¨b^vÏajºU÷å<ŸÌ=\†’ÏT37æÛ®š:¡ø/YQ¥5b¤¢Áß´¥z·¶¥âç{*‰&{Lªô9dW=½ßQÈå”ÏBÂ_u~ã°i/§#NGØfOïx>ò_ï`¤´›.§hŒ\k…TÊ5Ë)Š?ð²L:ßéõ )rq'£¯x¹œ‡Y‹ÔûR"K=ÞiGÊLF©,Œ,OèúúòH¸úúû[”—Óòqº`“2 Õ/:(€h¯Ké åCf§]ùþG:¡Õ Öòþ³Ëéw¢2NwÒ³÷˜Ç;Øöœï,íû„¤ƒ,ÇWAã|熚¾6¢¥5‰ØG(JøvqYjr©Þ!Í0{¾Ó¦‘êÒ©lÀN-™zÈYYʦcýШvuY=¢ºT'QãêQ£•C‡SÏqœ£:cYìê0ª¥2¸áx~aŸe=¿P§Yùçíϳ¦¶BvìW¦þ_Ï„vzÏÄéZœr•½²õŸë *}öžE=$—gQés¤ ëT”ääG!>ÞAzÄS¦¿}ãݼûý·›O÷¿ûïýwþá¿ýõ7ÿµÿöýç¦Ê 7¿Þ|ôÞúÿ˧l¯}ÈŽÿ÷ßC*ôûï¡ÿûßåÊüxóúHL¯©Ò¦™ø_þ?Í„_^ÿüÉnçýçÔÞT9?ÿöö“Þgxzí}þøúý§w¯?¿ýðÞûð7Èsã½~÷ë‡wÞß?~xsóË娤ôþß»Þï¯?ÿü!ò½8vâÞ {ƒ¦÷ó?áÕG¨Ý{ýþïoßýï·ï?}x/¢¿AêÏ>üoïo>z¯ÿøü¡ë½ùðûß»¾÷ŸÞuß¾í¼ƒ~½þˆ=¸ùùãk¨=†ÚS¬½O¡D=¿¾ýÏh‚ïýzóþæ#ü…>}|û_¾=LQä#ŒåÍ Ž^qVïÓÛϼþ|ó €ÊûøáŸ¨Óo>¼ûã÷÷ŸD1˜¨ªúõ7€é}þàýñ÷¿t"ŸnÞÿ|óñWÌï0rQâÓç×?¿}÷öÿ†joÞÝü~óþóëÿ„¦~ûîõÇ·ŸÿÉÇ2ôOå¨`Þ¾ÿûŸŸ«ïýïÞï|úìý|ã}ºùŒ­ãA_½_ÞBÕŸä¬ýãCG%¼~WŠ«¯?~|ýOïï¯?¾þýæóÍGá'ï—›7Ð5Ööæõ;û¯8á¿B¾²pÙŒé3 å¯Z×°ü‡¿<î0dµl@+Z•؉݀ýô b –ýùõ»×ïß@WÊ.hØ*^w’ÿM& V}òÞ@ RüñéæM^G¨AF¡=½×zö¦&”Z'Ћþs훓bÔ0A”ö¼ûüöïïÞÂ`Ëþüã··o~óþqÀžÊ9 ì¤5ˆ0úôùC9?eÙ7¿C£8UÐÊë÷¿¾ƒ:Þ#ì½ÐF 0/»üö½Â=À'î Zòñ ,Û_}Õ.vøðþÝ?%ºª,š×b´%XÿÏ7ŸûE³¿sÁO¿}øãÝ/ˆí¿¼ýxó—& üÏ]ïS×ûõõÇŸFŠ ^ÿ!û ¢ÍÀ¨·ÿùÑÕ‡ýðpæ= hû×?øøÀúOÕ…Î%e÷X.´”±¤C¢Îgµûîsß7½_?àð¢ P5ýòÁ AïÿÊ"S€š%ÛÞ‰¿ëæÏÿ¢Šàe“~‹9T]TYxÿ S ý5Qû‚<£ñºñ¿ï EâÝM—øH㿚²oP^+„ Êüz]ü¿àóÑÞ¾ÿã¦ì2¢ßQ*yûDký­×½ù?ÀITSqÀ3ó\}tô« )Rœ×Zf}Ô¡5ðSï½ÖÓÒ€ëÝçzó»ýæw~ƒÌ–C WG‡íEÜ^hCùŸ`oÍZ1A‚Ò~ó»j/2Û³@sƒ4UˆÄ=„ò1” M¤Ë]ŒßÿÎX…HjŒ¨06ý½fLo+HýÓÕX/° ÿÓ;ñþË‚?VFãžh/°‰Â_œÇPÚ~µ9£¨µ%'Ю#µf'LU-ÞâG[ÔB†µ„½Êœãò4`ùIüüÇÇ÷•9z÷X÷›×A\e)ªŠ°0‘O¾d@tÿ{ñöÍÍû77ÝÏÿõùáÛØÿ;ˆâ~Lñ¿Ã8 Óã§a?øÿûK|&þþϰ>{7MÄÞÄ÷²ïSç„Ož¬o~yû DˆŸÿ`‰( podÿŸ>üññÍ ¥üüö=ʵ(K|òAÒÿü‚ôä%ïÉï~yû··oˆÿú$ü¥½ÏÈÒAÐüÏ·¿ oÿíõg)þöá°J”l`iýòVHPè ˆ­ÏŸ<éxfŸˆø‹Î¼ùðË É° _ Øýâ+9Ô'  åàT…5è½ÿÅê ´r2ˆÀ»®@Cd`h¨f<|¤ðõä—oþ ¥BÎÍ €ý¼úˆ²Ð †ï>•¦yÁrzça<ä²YͶ/Ñ ~ƒ:n-SôkaϰËka]-¦èƒÄîb»ÎOwÛ$ü¿ã÷$ßüÿØ«¸ö²«Ëu¶Ù û™ý¡¶—h¬Å<Ûø^^L»i^œùÔ@–XôÚÛB¶'Û•OÍVË‘uœ’¶ãÓ|‘o¯©ÁY¾-°1¼anì=AÃk>!g¢ËÝúrµÉÈÍlšo&‹q¾Ì¦]t½*V^ö"+¶Þf>^,¨Åuv Ôé'ÆðN3èÞíøÔŒoš¯³ÉÖ'O*ùk@ƒŽ-|os™Mrüñ$»Ê`ãõ5yBA¥›ì§äÊ1Ôx9>ƒQ5ö@ñ&d²[gKì-*6Û|»ÛfÞÙj5¥þn²õ téú«·XmP»MæCÛ1µŒu˜à=<œî69Œü»Ö»K´d7av_D —cr,CÈâ^LAX°Z_c­Oyß{9ÏàÅIÐ#6x±ßÖÓ²AƒÄ­6LïI‘-ò3t’"¯2¬æe¾Éš0Q9zZaØðËñ5Úß¥Ó Zëé'`鉲>Í#ÚªÇÓ9ö\䆙ßäMl“¹€y÷‹rÙo÷#øÿÇ׿¼þ£û·Çic/ÿÂ(‰BÉÿ£ Š€ÿ'qçÿ_âÃR§fø\§ã]£ðg“¿ò¯ý«¬˜úsŸÅSÍyL~ÖÛÕÂãWŽ_µùÎÇÏÏáÛ_.è{‡ßµÙ—ÀNü¾!;}ïð»6ûfµ€þû9~Õfz¹Z_ø úÎù7ÿY»ðsúšæS¼è>VjªØ—Ê'@âõ å1ÐÆ|6ó@ñ¦ðD‰ŒgÙézœOš¢<ï9c™Y¾Þl½€·†×Söµ6 KÇÐk_AÙº~6š5`2›¥;j&›˜Œ dn Þì^\7ËMú€|Ó[ÇKÞÍeaÀáeÆQnÔ=YMIŽ81.´ÿ]q–u.vÛíùvŽÌ«A8çåùXVNþ¸/€Çå}ñFê{C”Ù¦Ïï¡û—Þ&•1ïYI_u)šäÅnµÛÈÍ[eéï Õõæ¹£™u³ÿøYXMQdkŠ»"§Íý-ºKxÀ±€×[Í.ñP,y±Ï3øÊ©Wf`2ï„QŠR^Âõúþ*[/\®Þ;_<÷Xï²þßɺþÇû·¿ÞtßüV3Çžwvóñ7Ð-»/_¿_SHüaišm&ëüR¢& ?‹ñ–ŽILHAªÈèÝéjuñ\k¼xäýÙ·Wõ $Ö¼wźÀªôìµ.P"TXn4+#ÈXkh)#ÑeܯíÚm©b>Ás3Ùxaâ;Šv^àTœyápBß3À›©—Ms $öT{â/È´|¸F&}>peC} ½µ¡Ð@äm¼äúO¿¿~÷Dûhĉû¹wþúý¨,„u®¨Ü•!¿t/Ñ…½<Çaõ¢ðÊá¢-rU=Pu•¹€&¼FvͰšÖCgêq`Ý‹ñbG¢S–çnÄÔ*„¦ÌRf%Åmº‹U›B1tø™‘»«Ä w»]Üȶ“®#µéa£^±ú4[¬^–€¿Ò²æEN”õªC£Ty®ù„‘‡r°âq]VF—ÔˆžÑQ Q•×ÀW¼þúÉ.¨PÍ ’A"ãï²OsGŸJªwínþê)ö…T¹ÈˆbÊ:@P,5æ;N›xózo«5s g@qw›èH×x ¾coñPd ò¨¸N2úd¾¥DúùÀйF^ÊÀ['UÊ]ì§]>¹€†]nQqk€˜?¡¯œ_ò@Õ w¼ÓÓv•p‚¿‘º!¨IA=%¾œy üv²È&x ë¼vôCðÉÓr`ìã5i]Ùb#Ù ˆ¯EVœAJQv$ç>Ð9è!8KØ?îüp/!,9 žsF~>9Å]©»U[è"Ë.Aë¦T‹k†Üb… C@D±?×xy­j½…~‹˜Ölcê»ÖvYê¸.;:ªu©¦ lòX}mäf 8*?BHˆYÒ.>qÅ$±ÊåE§Éè€J=p£„j›’>ò\ghØ¢• Ç´dd£ðsUæÃØx8næ¡ø< ÿ =»¼\¸*¶¾[.¯õ®Ë³}ctsÃòAÓyÄF®Þç…«U±ÜmÐ ïKsyØCM‚ØOg×þ¿îJó¡lƒ*¨#ý˜o)yÝ®khTX;àØËSL39Púnâ3Û­‹|3× a0ÈA9íjŽýéè4W+9‚cuŠ'S °—hBÃŽ{<@ef»/š:¼‚uT3ê$%ŒÚ×é 5q¼I60Ãuu¢¯ç.ˆ#Åó+£ÚŽ/²ÚÓ`ÝMï‘è|Í, —ÑZ‰¬sÞ&³¢F¤5¢ iÆ%WJ¼‘£¯‘|x­=7€$È”­n1T@¬òåšù¤‘ÏÄqB àÚ{ U?%Î*lvH&j¨*/íçD$óêéµµtK"»A"&z³]ï&ÛÝ:;.Tã¨0»2fŒ—È2Í'}´(B3ÀÂÓUA0± ©­ÒQðŽv¼.Á#êÐÐ!k.YNéóÌ´Bõ·¶O¢íÆ#¯<@[¬Š ÕÎ?ïc]â´/žp•4 %œùtÏj«‡õ=q´jun|º„¾Ò‰JÑ"@¹îuã9YãI`žâ®á\AðÙè&"pd×aæ2†fVgÞ2@b7ž*Ú1«‘øÍb¨O‘wª#åO—OI›V‹ 6Ñ4Ÿ{ŒãM9†ãµ ì!8HI ;À1ÁWåÉo€ôf³[fS‚÷;p÷ ߺ8»< C¨³8Í%ä]š µb’$ öu;ômY—«CüGIP¤ñÒ§y¿µ 0^6¨`ïÿ¯£Ä”¡)ëÖ-$‡{˜ Y#P@›.êÉ5õGpVþáÎZòѲ.ú0L‘;E\†-¹"wOc€åÂ8#¦œ8¿‚í6Ôê8¡;ÐSKÚ9ËùõûÓŽao„ªÏ)ÕYœÎÐÊ1ÉИ*EžF+BCZ]_šA_˜ ø¹Ù™Ûª£OÀ£027옂a²˜“è쯜¼*ûÓ'ÿ«q>Bç8wûƹ3ÆÉ»¢¥½ü‰7êë­tŽ}ˆénÍÛ«Û TB&—Hƒ AoIxe5t<ƒžà~ëùÉ„Ò `*Yq\ÃÞÃD»ùí]ÔN¸F±ö¯V‹)) ¸à/Ö¿pÜs~´¡õv]«xÖh¬ØbZ¬)Ö%3¥ VÜ{©tòÊUóöôú)ÞŒ‚iź³»+?[çÓÎå f×{*¤¢u&”WÃdéVx=^¶¼éTÖå\OÄO%…A(À¢@Ô*Ë9‹HŸ’¿ŽqUú ˆ^jˆ‰H‚ÙkÈ>ŸÖûd+ÞBâsTéAm]õÊ®ÑsCþÔ?ba ÔÜSž¼§xWŒVœ½‹‹ï¦ÄûŒ²ÿ“dÃã|A›_âÒ£›ÓlWLjêŸüÑó„w°ûZhÉþá‡%ÙÚ%|€ÐÕÇ_ÂÓU.$ÝÜ„(2 +”ˆÂ`½Œliõ„½R €n¾Ú-¦À8• «)MrQôÒ`ë,–çªN|!¢ôÜ U¦²§\h—+'ûcïEâö³,Ïyf˜ˆÞ\Ž'™fN~J[×O]k _4BÜÅQÓïvåï É+ ¥Êr[i>¢íµ+ö€»Ž×ÓÒé†ßîé´«š%ú —(  qÛÓ *Îj˜S„q×S;4b»r‰Å6«KÐY¶x{RF½ª…Å ì AM‚Þ8 ;˜´ç“–*‚•:éO‹.`ù"o¶û˜MÑj dÓFq¡]l–ã«Ö"kÇ-úÙŽ›í(p®K¼òË]/•å<QÓÜâªä®µÎ±æn¦•½× áVÚjøå¥ÒWÖñÔ!äl”xjúV­³¦%Ò4*½edO‘êYà¹Yh¬uCÄ,”Q*Tžÿ´!²DZ7Êšª3»{·Ÿ€l„WäéP—ìUW»ÐZÚ8`̳m¾º•Úi²0ôk¦àB÷£‹a’šBÑéââf¼uöÓ.¹ë†@1t¢¨#i%…ÍVÑ*ÚreÁSÔ䵂f€Á‰ì>”ÝA…ÞdÃ3²tÕ-œåñ€ê.úxúÏœe¨¾áx ×™t¤~4®&fºÊØBO3„µ”L—ÙgC°ã ' ?”œÉsè5)[g®©}—ij¼a”íW¨«-4 ¬­ÕK2nf—U)Vp›rf@ÎÀæEåÀ¦±æ›­¦ã¦W6¹[êF·ìå7_•…’ ÖÌ×Ñ‘6iâþÉ^v{¹’.• tb‘÷·:mºýš^ÓBå1ÌÈ= áùl#Üf«h§uW/D³"ÞfGjìÄè+’uôAÉRg„³ùÌnïI²Ë#yÀ5E§th•LV4>âÑÐÑSŠ”ä ¹hÍ!²ÀJ)Æ“ÉåÖk{Å:;ŸlÿJª!+ÒL,»Uë”Ä€|£`2Òx¤°àœ¼DØÄ:Õ¥#PÒE !¯ Õ¸¦ÊÅI·%ã]Ë?za×lIXi:º ‚Í@ž_®s{Á§S`È[£,Wú‘+è dðj2¹‹GÒš— 0*´×ë‡ðsSFzeš3‰ºgšØÅÜ׊èí㻬6s-¤M‡ ª€V¸!ž½ ÉR›=@ïŸmxlèø؈+Äî­õÓ/z¥íEsR¯¾£`ºVE=‰8©__Q\_Q¿ZÑ i®J§È PÃ*|J-÷ÑP@—@Ð ;Í'äç(¼âè;Ï6›U•áXE ´-@sãMƒ{õÙË9’ܪÇÐIv¤¨1XåK²¬âÕ>;x½ÃâC:h«êöJ@CΑ)Wq¿®òHÖY!b«-Äu\\{3ƱÍž­(×L £vC°*¼?Žð’Oÿi{‰Æº¦:&>Uþ¶—ÈÁi ^> I©X†¥²Âד‡hãåIJÖ2Bc3s/ÎèxéŸá_–+[ˆâÀIs5 iPødI (õ`V˜ñé^ƒY÷¬ë3ÄÙažhH:xùlôÂ÷^<5.ýM_hµ—TÝ ¢¯ª*Íi¶\FÅ Œ wA œ+tî…Ñ–ÑÞ”ÝÀ¦¾Y-³ríYþó´Tʮһ¤4þvP({ή–D)dePâ7n‚Dù"gá|[³yª$;Þ±¢½=÷Ö½é ˆÆ}>‚Òеátákc…‡¼øh‘¦aó4/çøPYn_?!Ë6<ºKpy-¼‰ÙeŒªøâµ/Zˆë:̹ê{mÚ¶d÷¡#øóbøK'tØòõ\ÚÐ`ÄÏå®™ÛŠ•«Ú•ÒqL¯¯±\¶a0°&¥Å˜é!÷©Æ\w ,|@Ÿé®WÏ‹o:²I]ÀºÄÓ] ¤3‡> š;†¦¨×qÁç*Ôg¿ûÀUou¼y^Úvw¥rZívïê*Å{ãª} ònJ§çÅ$€*páð¸×( .K&Z¬msÅ3shÂ]ÒM_¤¯“ /ìÑ­y;Ea O&ÀMXÀX~Ü„í‹f%º£ÓFŸµ2²±£Y‡¯’ꀱ¶ 3„ÑþÐÚ^XÐd¾§JwÞZ#0–u½œeöá¢æHBk@‡BÝV§¯Þ¥¼ LÒ–+C¾Ì\+频fV:.î&å…ÏfyÃŽ Tâ‚,Èô£(Þa…²ñÁûE¦«¡û©ß/…áb3ŠíÆ£&oeù#†jÜá>qlƒ}»Á¸Y¦´Qˆ½H’†€ûœÓ´,Œ²VeÈòvk vÈO?QÒÚùÖWýÁãJa¯k”%IdHw·(ƒÒ%ÆñF ãRÈ_U]ZdÕAw8 ÌšÑTƒ&aÚÔ—77Ü®ÔIIÿ'_õФ“uFo>¹leÚa9¾9›B3M…ms²'ê=«3ž]RÆv%lÑTÓ·Øu¦4Ýt uòöráù lɰƒÕˆsMâŠ\¯I"®X©…fÒ9>©^‡ÝK³+YZE}uUªõJ"¨HòÛÓÌ}:QL×f_7Í•#Ë:C{2RD­£tÿÒîÒ¸Ç5ç¡ ²fA++qû´r¡Hêêài(wKa¢íS·nJõtBy-ŠÖZ ŒµØîi½©µTÙdº õÓ=ebÃ"S"ÑÓ„}%OS,Ün»À‚“Aû$©wm qB)`J;½.·àÖÞF[0kjy­\Å’€kQu!dÑ´œâlWÙ—å5²œx;—ºÆÍè…ó(0}ô>/®›z‹hçý½EuB‘(”žùŸØŠÑ÷uÔ7ò£A›wlôü©•c™îÈV&v'€‡Uišü4¨³\ßRØ’º c½?È‚AÝ´ \•}ôà¤ÒjQºˆÈø ¿†4«õËñzÚ9O.ðGy9Öç‹Ý׺QIY‰|ÝtˆAÙgÅ(2mçÀj¼Æ¼Êvë_Yz` ]:š•žÖöÉ/Û:™¥v¾¬ÉxÀ0(¯ÕjÝöŸÞMö‹ëéŽÕqMj¯ºr >´  ZM-þj®ª¦?Q¥8ºê`‰œÿŠ÷‹Õ±3ìÐd럣¯³ø´\øÈÅdÜqš„°%k¶—¸ íŽÔEÀ”VOˆcÚ#‘í™HŠö s©ÆË2ä Ôl¸S’ˆX¼Rš'¯Oaê(Í P™GÙFhƒßG&Q,Á íÙï ­Fè—^å{³ö³¬5µ2ñqe½Lz\™ž,#ã¥Qß´ìQí ÇWea{Ððãîô}U‹»3 ·½¦V&=®L¢—‰+#íK£Ð5èb3¢·UÄu0ØQ‘¼¨¼V5˜ÝÂwØ£ »Zw‹ ÎÈ@üÄ=ÊògRþì9"¢û@Öèù­æ3ø½¢£]$¬ÉfGÏ|G<µ>¶ë]Ö-_úÚAaNšs«:äêL¥mÖaM¹¹AXúµG6áAðÖP‰J D“œŸTáQñª@¥¯òmÝÊ‚7²¨Ž|[âü>ÛvÓC ™ìÖ9:ºéÀÑ0æ!†ÙåÝ`:%í…TÃp­jšÃáÊwLfÑ{]íeéÔ:³.gÔ<}ÔÑ&Ù»"/¦áHº™h‰ÑHºŒh‰ñHºhh@Uàê ûm›j¤ï]» sRëç³tÅHýžßÇy¥ é;¢oɳ\së€:{·k²DkCk²°´Õ‚1SüÞœÊe8 ”arᥜš¡øRÎK¨‰\´ÏR})ç=ôô¨L· ,¶¼ð ú¶á VáækèCaº–´ã{›)âmO˜Ñ@£’䈭J׸ìÂn0 ÚœóGzð'Lè½)åqû^Ùé·¯5e8bcPö¯¡¹±R÷ÌÞa½£´'è-Ýí*jqÏYCÈLõm¬¹–Î_]Kk­¥a-v`—* r`I…-·ZÍ<&¨Öò@XÕ†·XÓ.A“gEø¸Ê)ý²-ÔAOÙÜy‘owDäêe°äS‰=v3á¾f¦ÐÌ ¾)˜…‡‰ê×Ðû=¤^Ë:4RÏ –}#¡×–e£\l÷³[>ò±É ÂОÀÝ*'¼’&c_úÑâ&Íjëý‡ YpGèèHçxD2YtÙçLAÞ‘¥€Z½Ÿr½zÙQVcµ¯uøÐ¦Ç†ôNG»5NÞ+ÇÕ,ô½,Òf‹z`OÑbZ9í¯¿ÌBñŽò9gQ¸{j!¨ÙÅÔLâv¬$¨½LÑV°árW€!ë”ÍÙ_ukáŽm‹¯‹iåÈ¿•£D*Ãùêt”Xé–ì­gí¬i·Z–»i€©¬0ÕËZRž~‘^¬ø”pR:]‘7„‘ïuÂh7#)jÀ;™‚ê‚‹¡Ü®\Ñ㮘 Ô\` ©v> žÑÞ¹ ,Ö®RfkEH¦šòçuÐÔê‰HžTŽÙLýDV.gaùÓQò%ùh˜tm E¥?DzÙ2yÞôQ%Â/˜BP)ðkê£û€^>9 øì# œ|ô ðÑ%@¿rX`¡ÚE0H„ÌDÆ’Lµðk›SöœòçT §9É©LŽ…ð›Râ¸Ún í¦XQŠõ¤XM&ø•ÂÖ—bu)Ö–Fø"Jn¤ØBŠ ¤1æ‰1OŒ…|‘à‹_$ø"Á©5j?§äÔƒœºSrêDN½È©9õ#·;’SOrêJN}É©39õ&§îäÔŸœ:”Srì’YMJSʘRÆ”2¦i|}_»ßÇÞ÷±ó}ì{»Þ{øÕ×ë/?Û>¬ãêã°ú8ª~„å",Õ–Ãqöq˜}eÙÇ1öc,×–Cô}‡ßÇ é'X.©-‡é#<úŽ>B£Ÿb¹Ë¥µåzX®‡åzX®‡åzX®‡åz}øê‡5…s‚jN`Í ®96'ÈæÚ¼¶97'èæÞœà›€s‚p^âœ`œs‚rN`Î Î9:¯‡tN Î Ö9;'hçîœà×<'ˆçòœ`žÐs‚zN`Ïëážàs‚|N Ï ö9?'èçþºâ}*Þ§â}*Þ§â}*Þ§â}Ƀ¤³1;ãûäoI>ðI¡¸à ®Uš®ÉÿDü'öñ@ Ë`Ìý]‘]]Òwáó…:Rεœ˜{.‹ûÏó:‘zØ\O»”WûÈèâ|ÑŒgJ 4ª»uiö{&¥G•ôx¤œ»Í€!O¦êçæ{áè&­RRÑ­ÂÖM:1Å_–$Kf÷ˆa˾¬´Á@~°ºÜÄ[Ôc4¦Ø-­dÔÈMÈj7?õFÓÍOëm£§¥NâpÔH ¡ï›'ä<¢^Eüªíx.Ã|wB#?%Ffb¸œD”ÞHÙaŽ: óaÝ}ôV¡â²Ôt MwöfˆGÔŒžXD£¨4Æ£¸|HFIùŽÒò¡7ê©ÂpËïðÝJãa%æ%QÙ­sÌ£žPm—–R¶FRQ(72‚¶”ñ‘D ‘z\¬'#ÝI˜ìp½}Áב6í|áO@ˆów¡ jº÷ã’\¤í¿Ú¡ìÙåjSdg£M~V4è|.o»Ëâ¨Zäúañ©éã/‘«©o4R‡ŸÒœØ¤Û¼¬®Iª«’‚çܹÏRÉ«Åt4WZ8RCk~ˆ6š6$qö,¢½ýª=oAwȦCg[Üz·8·GMGUµÃš'»{¹UÝõçW[5–S؃wìŒí3P¾ÅN…½ƒ†!Œ½Žb'1ô”«¦`¥z"¥i ß3£4òæ¯ÌÒÞÞ^<€Õb7Ò £ì>š›~²A¡Aýô©o,ìëñB°¶ºhò•!4V˜Hž Mïl*^غfÞ •Ï;xÞiϧuÛ« d8·#Iñ€7¤gzêl&S;TBÕÃŒJ€ -01GGŒ“F„8È‘¢ie;:á‰Ð ul©õ…ļxQ  yK”kµ¸E-טrQÞµuKHå,¡’m.©"ÀÖ¡ÍaßGs¬¹kn:•T•»u`\w„±Èç°²Õ*'d/Co_UÎO§±ð«-v„¼Óñ&ŸèXØ' )j¨0)Ùa‰kOØÌ£NŠÑѰBG{B-qwšD-î´–”?ƒ˜´°%ü°–T:ª·œ³C+ðrTñsÀWSâÂ`y]V-—xyWx²Œ*ŽøúßNíð9]´Ë%î:¢#xYïg³Æ9Æó¦£0¾lM!€1ÓkÑž1ïf¼:o6›®ÂײⶨÆÙ»ó¶³Û´yŽüv¹¤ ߘFž#«…¡D~+8º$Õ÷á葼8a‚7ÌÏÃ{$´q_/LìœY!f3‚¬m¢¾œÕ $šÇKjãœÑ岃ºª€Ù_Œ°s>¶ëȶÚ18÷¡Éǘjv®ønžˆ)rÁ·Â%œê&ˆÃv½" b?«XìÕͺíòâê‘Dd¹º&éê.½œ›^üÇõu…L£]x±Ý» °¤cE\“‚/ÛX…ýúvX ݼێž‹É>dñs9Ñç4ѰRO\m»g¸ìð~HWœbö“SãÚsøç*è÷Œ·=ð»£A6˜"+ Ê´Èd9¬£*Dü„ý29n#Ãk.ÆkÝ-“5ÛêÉÍ"{9Ò¹3+Oô­c÷¹ôh~bJ‘B“B*’:å#QªÏïZA7µ¢â)7önE_·ë·v(É6©e"q¿‡^sÊ¥L›b ر-µiÛç DgÔÆ”NÚ º©ÊB§åÆVÇ.K `×zlœtÒ[$mËì¤OZn¡Óì{‡/Ëw.Øs«Ë¢]®Íá¯EÎ$|îÛéSGo½ã%W™ƒ8¼áïh³Ð|—§£ÆЇzêé´¼ÁäN (Ç/;çËžÐ'€a<Õ~¶içÑ®EÀ,jp/©M@›–Ö€Í@,º¿h°±Î0Ëš˜²'Z éžõŠ{–› šfFÏæÕ T\ŽEo£ÀDkÑ[ºâƒ¾ ½ŽRèÀlYC¨Œ9x—Ö<²÷5•9O”Ð]h©Ÿdzw4¢/|Æš¯ÄYëʪ—k^ü=!%ÛÌUYémÕ—ø@_ø¼·Ñ£¶qX»¶_ êX‹¾›·éßÕå|tÕžTéëì<“ˆ\±Ò­¢N²¤ÒùHÚSÂ_n~/™†Eà_½B@iÛ üÍ©’¼ÇBä–'ñO#z£%…?áþC ^i‰&Ff¢“É/›=mÍ{|©7öé΋X½²N2¾ ót©Õ€ŠÛ øÕ¡“&&D2!ĨÄbc¯"(©²‘]6ÚW6†²±*Ûeã}eiÆ ç•T4j@¯é¼ˆsÇ “ïD *k“ÿD ŠÓ¯¸åÊ o…,©Q]‰ˆŠÄªH¬ŠÄV÷1å¶´Åju©\ÙËûÀ*7ggXƒBŠœã•"è#';ÂQN#Á‰!(ͨ©Ër …/`Š ÝƒƒÄòP«AµtXlUó*ö° þ)÷@$ÓyñÆwü……7Kc}*ÃëNJþȲ~tù‰.`ïÌQfÚäSYIuíé{ mÂ@ÃÕÕý6.ó9«ü¯^UÞ#Ú(×ø¾V¢²•°…曊¶ui´9*mƱoº´ŽïÅÌ ŒO$oî­ëÝ8é Æ”hdÓâ‘ÕsO^ÕãP,êq$Öô86s–ë™óF2oäÊ«V2gŽeæXË\Þfñb=žšr¥îÓzŒŒi Ø,e†RÊD?:öe 3dù’äÉŠ´¨(ñDÍ#úœÎ8ÿFUéÔs¸žÚ²)ݳ†_J~#Ò€_*ez]¬t¾ZýiV¬–RtÑ’± ~µ4É'”HDÄ Ðû2©Ò{™'ªd2§Œ[!; þ<) y„Š^ŸŽ§F3¾ISøej1í€äÐ-§¢$<ô„bq^9 ±ÿDã<Á/]œPµàE`Y‘é#×XŠ­=sdlÁ?hBƒ²-r³Re@â;mðšmGoQ§Œ' ¢øz°6A®·óçmá€[”8@¦vp¼Íb1£ÝwÅ|~"„ÅuR:‰?®6"¶ÎaUíœ÷ʈõ´¨èó¬“FB—äh«– iÛ~!=ìˆôqlÿƒ¥:ùJG+Ì`κÈèE&T[áRÖ‰ÌäŠÂFSÕ´KŒ»ÄÒñ§d赋>í²mG ²ØÝû˜„öÂR 85ù©RÔµ¥©?;‡é^rµ 4Î:¾Hä Ûà’ÊIÓ1ÕtBX ReŽHÙA¿’ÔM¿ÒTæ08P-ÊD‘*E©Z"UKTW );©2[¤Êl‘ƪšXU×US5‰ª&QÕ$ªšDU“ÔU“P5©ª&UÕ¤ªšTU“ZÕ|£†•¶aQÉŠ{DE%)*AQɉJLÜ'%*!qŒ¨DD%!*QɇûÄC%î¥lˆÕc…%BÞfc&ú¾1߯¶1#c踷gÐrü}ƒÆü|ß ÉžÐM·ü[4aó@”¿ÇÛžù¢»3î]ÊÞrŸwŸ›vÈ ß¨M´£ÎXÞÞ$ÊæÐû>“où¼ñåž³ÆÕ»ñsÀLù-8;~¥¥ßµôïZúw-½ü|M-½þÜgõü&³¸2éVG&¿«üùZ*€}*²<çhMü#É“µûMè·©{çxõ ¿y©ÂkzÝ臾9™ÿ0¨ûâñºï¼hP$3²”#{háã Q~‘"¡DR£oÖ´!L±Ë`‚è–»Õ ^%3ck b’KÏáhޤJk„‚ð|V»³¹÷GKÖUFç-ÃÇ4qÔe“·¸iòà5“÷“5Aû#7x2TCu]á§ŸÁ« ä°vuÑ}§îTb8xî0ÞErðösðÆsðª0—·»î¨E!Ï1 1®.-ù#åšbút7|è¶ÏTË Ùàx#-/ë5¡x2Šˆq›.%a©¹?7/øÅ!³ÒÜÓßè¨__î ¦â•‘RoRŒÏ£"¥x®`)ž+^Šç  ?mŸ6Å3ÐBÙ=¡et¿3q¥ŸÈh@Ý•Ï ~vÞJ)¯Û¬ óâý; »ëÕ£I¥ç•n;”S]Ðn —Ìœ§Ìdæ5úŽ[ÓQ¶8P`P-¢­V²ÐÓŒØ9Ï•§±R±Ë.*…€ …©*‚ùÚ’H­ÎeO¿æ—n´fÐ!,; ´œ„‘þ bˆ`ë 5/е€Ça}èÛ ïìí©8®TѵžÙEú uJ°J¸§ ® uä’„…âgW9ÐDèS2úù°?l^y åÊ èÞ3yc=¡æe2Çtqíá€w Š #¢gkÙ3ŠLž¨á0© ûý;5N«b“¿Ê¼m°bùÙ0>óçFsq¥¹ê„5V Ä»Á—â!{ÐÅE~†Ý9^Y6ͦÏ<£ùÈl^¨ÅWZn·„<½ »6Üßµ'Þ³€Þo<ãz@ºæp¿ã-ƒÏ@Ãt“¦Ñ « ýö‡±ž¬^Dbʪ½A4ˆÀ± Å8Ë‘]¯èC˜Å@<Ó HÓ Ê{AhæE×8&iÐôÓ!ð+¯œµ´£Þ0Ò´úfc7)4až±ÓQ2„ÿ{f,Ö÷F]&nšRrFªö~:èEQ!Œf,LtüKVÃBƒý a0 ÁÐÌZB¨ ìGCÀnÀ«xH00³&¢V@û0D\0ž‚þÐê@*—Uh°üްd¢A˜µÊ©aõ`‰¤¸HÅ”A€µFeVuv?ô`îÁ2„½hh+@&0¯ƒf%ìA¿ãÞpôzfV1,@‘Á ú¸œ¨q€cì›Håº\äH¢t7z˜”بUbÖ¾Á ÔNpÞ¬Äb¶¢W  AÃB&=àƺNc1[È~ÃÜÇÐÕ0ä×(2³&"ë0’,?@m0ʙŽAœÆP5ýÆC9#k"†íBEI`>R¯žÙ×DÒŠ~}çƒ^h2ÏÐÌ*‘°×æÆ,0X~q h3ì™YŰXöô12 ¤&µ…}3k*! ð©Í‚fè A(€Øt‰Â!ô˜*Ì( j0€ÿccí«u| Ó,™z• Ê»‚¼‘–W.DXN@NaÙ@&à5qˆˆcå•ü%ØÂüS"v¥= ßƒ¦ðR$<ˆ£ð : 㚉>èyÅZZÎ}Àˆá0„Rkl’qö$@¥“¸?:†) Ï05ë•«1Ap½HÝZ$IšXyïŒ2ÅP*Á5ô¬¼jl)Ì*LnÅ!P9 Hâˆz^1¶Ðjä,P'ÀVÒÀäs©ä‰1ð +àsÜž`ÁL.I\:Ã^ ø'°‚?ÎVÞX[À@ˆ$쀓0)Ȧ­¼rlá ¶‰+¸}X×îƒÈ0W}$½þS10ym¹,a~C 4Q#ÿÄÏ€ø½†g‰ÄI ž=$7Àz°ˆ¡àxV^96@ò³Ei‚ xeõAÐQèmoýJL€<ÿÑ©H®–&LJ,„ˆH/¬a`þÉЬW®MœÞ¦ *q䄉…i$å¡€>,!áàÆ±…g©¤¥ÙI …€Ûƒ“ l|H%ЬK¦,S_ßÊ›*|éV3€€$}*ª¯ ƒß§6¿ïK:äÈqHÃ’À#¤_êK±,B€Áä]Á0ÔAß—ü~+2£ X‹ô 4ŒžY«˜Ð&Öu«z’p´¡Õ1Ÿ @dn +Êf)àଙµ'Ř×>®˜£>4ÒNafíËÕÝ z!-[X…@ †ÀBÌZ%Ⴕ“$ˆ}S‰¼9ͬrm ƒtŒ´Hxf'1c_’­ˆ„ïpÊQ"P R3«ÀA‚¤D­^ r#È= ¡XÃ’D+ @ÈnØGÖ˜:AfSâ1”³öðƒXŒ´³ â H½5)³öy ì dœõ@™AÚbKÊ&ó!0¥>ÈÒ1pô^˜Y¥È<Þ!#‡Öa¾a¦Æ¢îKÙ–{ x:$ 0 ¸¾™U`@`J ½Ã´`YÙÀ’TVh :x°֜ظ'å(àc¨•D(ýaqÆ©™U hõp‰:Œ§’<Ò È«¬’´‚,˜¢@².ÐÍ J€ª‰>¬DaÈm=XõDQb,–ô3«$¬Ä\¨ÌaoðÀ¸ A®/éjŒÂ.°Ì— °XèôݬU r¢EO\ 0»2IO¢ h†@k£a1aM¡'&HúRÙ CÔ'‡!1C•"HZ ãòÜ둈€ÂšÉû©”z”D`j“J0= Äq00³ Ì ˜â[ÔRQŸƒB@ç̬‰d,ÀKzÈ\q© ÖƒÚ¿1¬T‰‡P| ³€_Q€LÆš‚´'EÔçaQ$´`’·„fV¬!j™A„Òq´H6Èj†, Ý˹_ˆ a«+D¥.²jíÉe¯—†(š£ÂU–ZY¥, €Œp‚pV¿ ‘ÂöͬX ÆÀkÊ 6…kËÈ*5Ì>*¼ fæH ͬ=Y+4Œ"Es ´x˜˜8ÐÀB!ÑØeŠ$~˜$vúR z=„µË É ,E`í¦$RrÎI<Œ) s´j¶ËÕ÷•„Z4 D€{ÐÀI]V^±hü@D †@C”hBc+o_ÎLÙ0 ¦cTŠ…âÀÄ3ÉG¦áÍ% $Àõ¨+¦TØ—Ey#.  b B¸Ô{C«^3˜ƒÄò>jM ôöj¬z%w@kP‚ô;E vÔ$íY¸#õ|àù¸âPÁN°RSú6$3…,ÈDy"Pp#×ú8Hš‡¶D3PµQ/6ÍM9³SÈ +Ú ì(ÏØEHÚ¨†;Ò‚€Ò!‘`ư&V^Iö€ãRö‘[‚ ˜ÙB f%G$c'* =Ð{±µ.’Tjå°2Дšc„kb­ ÉS£Û]ƒ!, à% ER ¾‰À³!Šè€ £Ìí)&|S©•£Èž’a t1Xp( ôM8¤Êô‡‚*,e •A€â*oV^M+Gð“”t0àØö:N¥ñ@ÿ£9$Ë^ФÒÒ€úJBa¤¦ FS(Ò(Àõ­±Éµ ôæ„u4)ì¼ËÒ"Ìú(·÷PE*L̵oZhs†h¢ Ö€ð®gÒõžE€â´U”Ý%DÓ¡•Wòn?ÄìÌ!,¡ ³ž€H€ê0 ™ H<€56É`à 9(ゾKJ&Ñ+¯T¡ ÁÚÀµß')ØES%‹’>D«*pë^¤¬2ddÍ…ä±@èú(g£–¦žõ¥Ê‰„º‡š)’ôÀ~`­ã¾Ü¸¢ n€ ˜,(P“ÂÀÊ+-$(b£ïE 2è±ÕCÏ+×fŠÒÓw†h‹Š [8ÙïibZõ€Á‚ò‰›2QhÑɾÔ;A&ô9:Å­$4l$NÞbߟwçkßÿ@Ðöãݦù2+èͤº`1iÄMÅö@‹# ˰À€LMfÒH8çgU’ˆB9ð¾.\1‚°M 70[È|§ô0à¬Q™Uô%¬ Å$ƒøfˆð5nʽ¹(MpK„:àýÕe3«èkŠfD…Ñ≛§}佑Ù×Tô5p}´¬0±$/FÀfPnˆªïi­ËéæQD¹:E­ dú¸ƒžYbÕ ZÚ)¼‚‚€¶Š íš#‰ )¥1ÚöAe. ?°k–ÀZ ê'Ô LH=K!.Û߃vÑMy0-(ü&4Ot¡J| ñA€Œ´_›ºÑ.F¡”€€ Ôsò\èB;Ð(zh  ºUŒòSbäL9gÍX €DHŒ»ÑCSúŸ4zœ“v•ÍQ©ÖJ}NTƹIœÄz4Ôâv‰•ûˆ8°D€1ÊE âIèDeÜ.G õ Ñá>wd%*ƒ^2îÁ¡‚Æ!XÓ‰™U 2,µ*=ÜnNÙ ›Ãˆ¡Y4ß¡õ;NAÐE_‹™µ/–ZzûÖ÷°º@@±î P; b .û¨f$$Ö-- HSíÊQÝ Qc†ÜÑÔ@Ü $•5r,Ü Rè: €H}CÏ׺P % å'@ð W]zgGÂALÆß BÿÜSíš%‚ãf<Ð߉@âæw`l’ÜR¼™<œxS‘Sf»‚‹ùøÓ¸‘ûWê”]§Ð¹óGŒi;Ï7Z3ã`å‘')'„¶€î¬vq¤°ë4u¹^½È§ÙÆËÓZãKH»’‡2AðÁƒhyg;§ƒu«"+ȯ”. X-v” ÝK»¢¾þåõi÷oÒrKЩé/hÄÆßÕÌ~üÚÞþìá/¸w¼àQzc}þøôùõGÏûËö·¿¿þTŸïÐ{!Nª¿’Xì†gýx—â¡÷ "ÃcSþ¼þôNôñœ¢‡7ëó'žŸÛgèk³/ÇÈ~ðl½üð!O:Ögz¹Z_ø úÎù7ÿÑÎÿMóió!ø`±[fë|2^” ˆÕøF>›y V•Ïp¬0âÔ{™ß/OÓˆƒÛ^¬#ôMžÅ'³®·á3T^þ¢;PLc¼ƒ×›çŒd>Î×ÐVtÖõ^Ž‹"[ÛÜ G¬7t5BæeEö"CiáDHÐÌ3S~ÚeèOæ4XQÊ‹ßÛÀ`^eë¶igÏÐùâ9üøøþÓçîœóÿýõçߺ¼ûëM÷Ío5óëyg7{ýñ—îË×ïß×Òå³É úã• uºZ]<רO— åÅ™õ $V¼vÞcUzöŽÂ{”A²YnºZ›Ë5´]ØÀZq./ô›óü'/L|GÑÎ ÷™‡¡8±‚.dÓœP]U{â/M7¯ÖóH|CŸ²‰·w¯?ß|úì}úýõ»wÞ›?Þ¼ùüöÃûçÞùë÷¼þøO/ør±¦Â¹¼€—ÂÝF5e“õ¢Ð¦¶è¤ÄËËVUtZe.  ¯‘]A3žfE»@ØáÜA=\R’2ÓŠçntÓ*,OÏ\÷‹ŸŠä ÅxY4|¹KÌP+ìv»ˆKÛIב‰Úô°Q¯±É‡³Åêe ø+-+^o‚´òªC£Ty°vÊÁ÷Ÿ\—•¡¼){–eU^ƒ2^#!½\¹À+&ðb¨ìlŒ¿Ë>Í}*‰Û´»ù«c¤Ø^Bå²"Â(ëѰV•_!,ت¸>°X­™§ªn¸ãòQ‘7ðw¶ ð]Ÿ§•7–@Ž `ª[ë¼vôCp¾Ó2`ÕcX›ÈÕðô0%¾²ÂÄ™·ÈŠ3H)ÊŽäÜú ]ŸÌi–°Üøá^BXr<ç6ŒütPStÅž <#¾ñ½5Þɲ¸fÈ¡r»XÍjjÀ‹x­PëåÅmìC}—ÃÚ. @×eGGµ.ÕT!/Ô0ûÚÈ5Ì@S~„³¤]/çùd.õy–b~d¸º@É_ªmJúÈ pmðì6Z)\8Ö %#…Ÿ«Í°ðP2šy(¿BÏ./® ÆÞt·\^ë]6HÅ+1©|ÐtA±‘«÷yájU,w SÎÇâV@<±{ØCM‚ØOg×þ¿îJó¡lƒ*¨#ý˜!ôÑ(ôß‘… KƒÎnYtÄòÓ<^¯Ç×¾›øÌvë"ßÌùh3ƒq÷Рr,ÚÕº“Ò‚WÓtÀÁ±:ÍQ°ÝÐä­PÔÝ®Üã*ƒö#Z4uxë¨f`i!²o\'å3Ôrÿ¼éTxsšw¢¯ç.ˆ#Åó+£ÚŽ/²ÚóN¡ÛÐ1_\íî‘è|Í,çã3ã:/sÀäC뜷Iel‡‡¨i(hDš1Ǹ£K}äÃkí¹$eÌ ¦5°º±ø:µú•׬ùú{ U?%Î ÃZ‰ªÊKûy¹8¶o,Ý$„Ènˆ‰Þl×»Év·ÎŽ„ Õ8*Ì®ŒãYyìj—ÖEèXxº‚^#¡ ©žw Œf‹| ÒÎZ \‚FÔ¡ C<Ö\²œ—S#nðekû$Únü8Ò.ù,VE´¸•BàÍ^Ö%4â1.`Q@ÃPÂi‘f¯®‡õ=q´jun|º„¾Ò‰JQ¼%‚äºÓLÅü‰).»Íú Zit# 8²Ô0sC3«3PóÇاŠvÌj$>EƒƒêSº’FŽûéò)i3šRß|îuJ0Ž7åŽ×‚<²p8à 5ìÇ< _-ïÊvKâ?Úµ˜¢¦»uqvQ A†PgqšK È»4jÅ$Ic¼m¥¾Û¡oËB¼|#WûQÒi`¼ôiÞo-Œ— *X'À{Åÿëè1e¨Dcʺ½ Éáæ3Þè hÓE=¹¦þÎÊ?ÜYK>ZöÁÁE†)r§ˆ+°%Wäîi °\¼%–|? ±½Â†Zç#tzjI;G`9¸v_bÚ1ìPõ¹1¥:‹ÓZ9Æ#ÚáS¥ÈÓhEhˆB«ëK³3è ³3?7;s[uô xFæ†Sð€sý•“Weúä5ÎGˆàçnß8wÆ8yB´´—?ñvx½•α³0Ý¡±“DÐ3¾~¼ëi@#Èò- ¯¬†Žg¸çœ‘%§Üí&+ŽkØ{8h p7¿½‹Ú)×(Ö>Þ9I hy±£¿‡<šŸÊ·ÒXËÍtg±.™)]°âÞK¥scú,<½~Š~ ˜V¬;Û¹»ò³u>í\®`v½§B*ZgBy5L–n…×ãeËÛHe]Î5ðAüTR„, D­²œ³ô)šéÉëbÅÚÐzw¹½Ô‘³×}XMÙÖûd+Þ‰é²W]ׄI½²GôÜ@õXFØ5÷”gï)ˆµz5rújL.rÀk˜ï0ÎþO_ŒóÅÑk;'£]ÑIz4Ô£ö?þè ŸŠøýFóáñ¼~øÁQ’Í]š«M½“ËRºÏí†P…ГM­ž°°WjÐÍW»Å8§2bU å¯éŠ3ßëÌ·RÃÐs6Æ©¥é#j¹i¦~yé1s‚”š°¤H´!IH”³¤fÆŽ:‰‰èàsƒ:šrÏžr¡]®DìÚëUà¶,O¦/ &b§7—ãI¦Y°ŸÒþ÷S˜ñE#8Ò¨éw»òwÐäÅ‚l¹“µg ¹·+¶-€¡×´\ºaM]Ó$;íªf‰eSEªHJ þ4ƒŠ]ˆ™ÂÍ_±D]óõˆ›Õ%èG[àh°Ù¹µ$nXëÁK¾Øà5¼ró€Tbap+ÂEÁ‹»«»äãé‹q±®Úއâ®É w¼MoðÑ ȳ>c <ÍÖRòMæ€ ÁQ+\˜,øP’6Ü¥›£l_Xšd%AôÔØØ>…ªØB³pÁÚZ½' ª‚£à åÌ€¨€Í‹ÊÓbÍ!ù"[MÇM¯lr·ÔjVÇ$ÀÌ×|Z‰Ï›£F—'s· io×cÙõ¾ÕëDÇ´¤IAbX¼,»\-h…ëç;êôtÝ(O?quqGfä³…@x¶ΩU\Ñ:èΫǬˆ÷¾…rY=ôi1]Lä5#DËgvÛÞ¼jÿÇ5 a‹ê/¡¶Œ°¡ã”å*(dÈZ(kqo<Å8ðÚ"¾Á_I‡*3Q¸nÕd$§1ß(˜Œ4Æ&ì8'/6±N*BÊoL;xãÕyˆÊ…a`WÞ^Ø5[š}G×ÒÙä4ïªß´ov€™0ä­Q–« ýÈa×9jÛ4’`¼L¹µF>Éšqñ\Döá|¦*ŒôÊ4-l‰3¨öêç¾VDoßµZ‘µÒ¦Ã/T @+Ü’Ç^ÐdñÉž@ ÒÏ6<6t,\0âÔøœÖO¿è•¶AÌI½úŽj€éZõt$â¤~}Eq}EýjEƒ¦aÚ)=1ØÈN梖û€h(~K 5¡Äe ± —°*Š@ÒZ€ÆÄ–|Û½ýV4s i¦z dG:nÃU¾$k'ˆlÓ¼ÆHektkƒ¶ª¾¨4$÷™òØöë*d"¶šÑB\àQ´Åµ7©ÛÜá†rqÍ2jGºÈxy™M؃Vnðëš>è-ø tCøÛ^"Û¥1P¬*”î—a©59]†h/âåIÚÎ2B0Ô=¨g¸™¤œÑ3 üËre ùØ_ò¡! G)I¥&Ê’;‹Pº+_Ö=ëú qö[ç#’^>½ð½ÏFgKÿšíH½¼¤ê^}UUiž¬å2*N`d¸5Ià\¡Ç-Œ~´ŒFð¦ìv€tåÍj™•kÏrj§]Rà”.¥y´ƒ’Ôsö$J¹ í^É̸£bà‹œ%êmÍŽ¦Çx‰6ÜÜûé¦×jèû÷¤žËzìô«kc…‡\ëh‘bT´Î’­MçøPYnPy7%¡°ër@¸p¸Ák—%-V‘¹â™94áÃè¦/ÒIÐv³Ö\Ž¢0†{à&,`¬?n †>³Ýûh£ÏãkM³"Õcmfcù¡µ½<° ÉlN•XËEwÐ#0–u½œeöá¢æÝAk@‡BGVG¢Þ¥¼» +reÈq×´‘^ IˬnNâ ”!ÅãÙ<‡ô…†]‘o}U‡ {]£, 5$è¶Eq ™=®§R®”òêªê2!«ºÃi`ÖŒ¦4IÒž1ˆèz`îR½"U–|¡+Bc^LÖ)£\©«!@áÝôQC-+Ì‚îã¬H{'« HŒÂLA‰•™Gt¸ì½ÏªJO#èAˆ‡ }PŒÄ)-UÔ=®lŪxõ˨Ù(t7ؘ, T¦ìÔðhí@±æò’<0ÊÚš.ð¨(ʃ\ ‚o”?TIƒ„„0Nˆíal…ì’j¤Z޾wŠÆYÔjU>Œß =Št4'l¶8@`ÓGÊ­T‰hÈ?xŽq³õƒÌâóŽŒËæ¤*ÓܦÂF¸qU‘Õc)Éòc»¶ *4\ì:SB[:³‡/>V¬<„S¦ £y.d\‘‹ì5 ©k¯P–C:ï&5Þ°áci¾$‹¥¨¯®  W‚ŸÁÔ üwžâ¸Ù× ÏDFT¾•¢¦¡¤I|þÑ,3nHIu=ÁÒºw;]ˆ³d/ÍY ö\¹"J™mPò©q™‘Zÿ#ÝF²suø-¬ÝžR°yzäÞáoCñ>Ì~E鯮ÛÛ^uÛò…~ÈUžHEó᫃jÞ)nÞHBíWƒ©˜æÈþWÈí–Æ=ýä¬Ã'ïã)÷aôc¯‚ÉKthr § w ÚYnLNså'°ÎÐlˆ«Lëh@4€4îqÍÙK 8‰—"êÇÊJÜþ„\(’…º:xÊÕM–éVA8æf(„K:t'‡±Û=­w"OZk)À'9a@Ï}ebjž"¡#ï<ŽtOÉÄÓäGGôT‰BøAvUˆƒèåv‚r´Òx:Z¨a3#“XS£¯iå* #E4%àíþӦ௢?h -Ĺš²?.Ãkd9ñ <ªr… ç1Lúè}^\7õÑÒÉfu½E㺨žiª°¸ë{>:êùÑnɆy=¿ ¹Ìa^Ó™D„èb³ÖA¶AU¡†7Ò-ýDé¥ c½?HÖA«° \å§Hg† í´Ü“§pïÖ¬Ö/Çëiçt<¹ÀlyË·DV€Ã‹ëÆ%8æ_™ƒÐ8ÔXW¯¯:†åÛày@f€XÝöŸ> v"~Çê5¸ÃÅcä0M§³[Má¯æJg:TTŠ£_–Èù¯x¿XÁM¶þ9jþx ¤Þ§­·ÂG¶"¯ ®õäv@w 7¾c¼%kL¶ŠKÌvG*öwAÇFÕâ’öH4@{æàâå3Ì¥^oO4|^»T-…éI¹Ö³X^À‰ÍìFWض9çô K£aCnèã6+¾´£ŠsAºôQ w og5•éX=¿Ãƒ\ð»ZwEâ'V™ë!¯Ÿá]‰¸š“凌ÁQht–oHˆ¶Ÿù•ÖK¸Y1éxçz|v†édžM.X=(ÝËK&æ].A èââòúdŠÏ™ œ•qáÛ1+Q¼Á±.“è‚äÊO/»ÅN(’ã?³J¹aM#}~Ú­¶#ÑÇÑ1+‹HI´Ù–R "v³"§Ìƒ•ëÍaöeºbc˜ zyzùý ×xæçþ³æÃ1@Ì@Ì æ{€˜ æû(Ô¥ŠUô&¡RZmW–.˜9•@—¾&N¤ÆúFì~âœIz/k0iC!b¹"/×+:ôD¢´ô{yæW+­¤K¾Èé4@?™ Tâ¨äÛQß x#‹ZàÈ·Ç@c²[çèÿ¤Ã#.á?<˜ÑZûç¦ÛË^à4 ç¦9®\q3Œd½×Õ^–¾Ž3ë–=Í—Dh‘½+òbޤ#ƒ–¤S‚–¤ƒ6óT…˜v®®°ß¶©FúŽÑy¨0'µ~>ËÍþÔïù}œWª¾#ú–Ñ5\së€ú˜zÇk²LA­ÉÂÒV ÆLñ{s*L”±Å]ÞhÈ…—rj†àK9/¡ŠP@.²ä—@_ÊùÀ=m==*Óí‹m—äQ?Ã6áºÃ®…@AûÕaa##')ƒ“šã›{‚+VàºQ÷fHª½{í3ˆá®›íÈ “Z0Rû#`¯°ˆ…xvBUùÚî%Ƚ…¦Ú\hÌ7½BŒÕ«¿Øöä~`GI·rñWD{"œfîˆÐ[_[ë#2n»6„ÓZSµzpüÚäyF¿U½½MD¼mPÛF42Yh¥ êXZHV¨`çB9bº€Oâ„QÍô•Åâ• &ýZ˜ÌQ¸å]'Lè½)@pûÚü’û…_kÊpÄŠì_CóÁ£îYËê¥u8Aoé¶HQ‹{΂׷±æZš\ii­µ4¬Åì’BD,©°åV«™ÇäÕZÓÔðkú¾ö9ëæ1>ß#N4ß¹rÂi®ó¥ï’ñÕÖû M²žÐ¹‡|×E2YÓØÏ á\GPiù¨^”¶^½ì(‹òà‹:|ºÈc#f§£]_E§<•³Vú^iSL=°gr1­œ,Õ_f¡xGùœ(&\œ–Z9ªÈLâv¬$¨½LѨƒáfR€!ë4í°JûÂÑ6?,¦•ã¥VŽZ© ç«ÓQb¥;L2klg­˜ ªe©k&˜´îWÓ©¡T¯Ó’Õô›^ðæ¯§„«ÒW%Yðr<'l0ò¢¬¾“)8Ñ.xÖžÛõ+úoÜ•gGPŒ½Æ,\` ©vž žÑÞ9¢,Ö<ò‰‰ºPq×8ªÕäýÚëÔ݈å5ŸÊ›òõƒ[«Kq¹zvë·ÄƒV×uœÆÒV‘XF8 î2ôùLŸpdô»“ÅlÑ&õ)Õ¯Ëñº¼“âš/IQ§ÄyKÔÙè\™aCË^…£(,Ÿ@¥…¤vQ¦Ä˜i)צÄZ Þ<ÂZÚ Ôez¡§aí3½öÖ>Ókñ“ôê‘2Ò‹vÒ*Soé]»héÔ7Ï2lIЃ!Iù*Z0ƒx•…Ú›|DïËW¥B·Ú’V=®o™‰šÈœªÊUUR¿op\ ¼UNy±ÙÉíÕº.}têòk´°Q­·CBOCý°5´6q%¿4%¿Äù„ÄvIxñyN©QÛäáŒ5àsªÂJ:ºuDŸ8 }€]v¹¼üÎÐcÁ1ù‚œZVòÐ#ûe&ÝUørtö·ÐF@•ÛÝ6³yÕ˜CöVzzmW ­Ë»`xpRÖõx Y+!U€ús¿6| î[VÂ¥ØñPô°'8 ­<šÑ}áQŠFM>)ĺVä£{)RX¹ªÕ`[iÕWz Û´üШBÆ-ÑW!3Œˆ…m$sMõ3jjÅeb¬Þ_ê'’4õ0+«˜¹ª˜•U  ge1 8ÚïÜQò8a@§Å¦?DúÃÜQˆfÓÇ­`w€}Úøõy¿×çm^ww}ÜÔÕoÐH)=kFX…™ˆ'í4¢+=PFÔ„™Ú‡TjÒL@2uÁL½»d$FVLGÒÔ @—»Õºnÿ“££j{Vû·?ñs‹ýÅFH6M¹Ãxë-ÆÃ;Šf‡îÕÊ÷uhÿv]ýèZ•ÄÜ"¼ ߨöÑ“ÿIœ8dÓ8ÿU迊üW±Vâ:ð‘vù³ÐŸEþ,ögXJ ‚¹?£‹”/CøÁ?fµÒt»ÛÉ„±²YE¸XD4³Ô¯µ“¬+®î#&\ 4ã)š$îÕ-Ý‹ÞörºO­\ã½^…ôÑwŒß×~ã¤Sz?£÷3|_©¢Á¨„yðzeÆ&4ðõ“ €WËeaƒP²6OyùT)h;h¹Ý®¤T ¨Ù J?å@Ò†V5Ç—ôN ¯ëqJ& X9E ÿ=Òd‹i*©UÄ¥\`L“å"ƒeÿN‰œžúK¼´¿g3xÆ©Ž 0vaôÉoÑ7—&¼Æj·§¹bTÊŸ ÏòÃ?ÿ‰}tC®ó';ì@&îäÌ7êËaË£átø7»ö uñÞ¸C§Ø  (ÔŽ&ÀyµÊ§x· ‰Ó‹õd„ª[Å•©ø[‹åʱ™2Ÿ@)½ø¥¥mÃp4ì†QÅÃdÐÃh˜Dýa4í¨¸ÒÛ0Qì0JÓh˜Q0L“($±êÛ6hÇÝ ˆ†áCO‡ ÆÒNÌŠ"<%a?ìã¨ôà„ƒa¯¬'Š0Km ã4‚¯þp8ŒÃáPË0t7v4 £~Úz!äëkYblhØëÉ D^ÆC¶2K#Oº1 ©? ƒ ‡i§a gÁÎÄ1 i¥á LÁpЃÁëy°7)Œ©¤1t5ô :®7ãî$ݰéƒtí„à éGýXÏC@¨ôÑ úè<ŠqJôLØXÒÇ€Ý)ÅvOÓ Ú4æ0vŒØDLœ`ˆîAoÐO‡©ž ¨b—"®÷†Ép¦½ãÏGz–˜êö‚x‚½Š`>“aßpÝ\ÒÞ¤´–âW;”ï/W›";mò³‚0Üç}?IPP.F¸Ÿ‘«ð©éã/‘«©ûÜR‡ÇâœÝl¥—í¼¬®I"¶ æÜ¹ÏRÉ«Åt4Wê²KË9‡˜§isAhå" íU{Þ‚îïC‡Žµ¸5ôjpn†š;¡ªj‡Gv÷r«º B8Z%uB I#”ö¢´íå[å„§S”=ï[4 A«·½Kƒ÷QvóbžÖzÊÕ S°R=‘Òj“öº9º6•HCé㬻‘^%¦ÑÜl”x kE ê§O}cK¿k« †[¹]ƒ Éÿ©é­¶+¨™k®@^ãM8ù¼ƒçö|Z·…²sË‹ä=x“Az¦§Îf2µC%T=\À¨ÄˆH:Êáž>’âaú„Q¡- *]­"Œ©Á¨=µçÇÔn,š9. ¹jEÊ蜠~VìKtF¿ÚÂPìŽ7ùD¿« B…ºH=;,uÔù :0QèÈB³&nr‘³Æ–2¥Úir¥vN«„VêQGõÎc†o/G•hBK¢ÅB[±¼×`º—K¼J$Tñs9Íç4ͰJO\m»g¸ìð~HWöRã\¬9üstÆ&Pü®Áh-2¦ðÇv™2-2™Þ¹­ ­ÅNDäU”Eò–á|í™§OK2íÂÉQg,Xs”I¨2¬8<”ê#»v9BÍì Û©‚Vi<Æ.ød!ÎB¶ófk6IóèÙœ¦ûÎB!¬Òªê*ݚܿ[ Ÿ¯LÑ¢‹‘êâ1½¢cŠøEt"ÖgPd cômpuJ!×zT¤¬9ÐrðQ¨R7"í©©”#QBwa¡Ž’}ʵ×D$„Oc°å_œÊ¨,L)˜‰¿'$b™¹*+±âG¥úè Ÿ 1zÔ6ŽuÔö«AkÑwó6ý»ºݬ=?,ÐÙ§|Jïðò˜ÏQ’ys¢®I'È,kƒÅIá_…|(n˜É‘;9v&ÏÜ•Ìܕ̕ìî'ñO£ù‰©©MŸF“°¯´´Ò"3Í9äñE8b½±]4­7‘zc˜¸ˆÕ+ëpÀ«0‡ÎüÔj@Åíüê ‘²‰Ï‘xñª°˜á«JFªdd•Œö”Œ¡d¬JÆVÉxOIš+è³c¾¡?Žé†¶³&°TÓFCW Jâ¸UÉqæHfŽdæÈ‘9æÌ±ÌË̱•Ù½«{`±-V«Kå>FW­æ3¼&øN Ž?t>ÂBo¶« ,Ä?Å>*]ã4°Ön«ŽGHxñÎT¢¢°Xtž?DÙñäÅYÖEâÌι\ÉÒéҾΜBcæS³ª:‰O·©´ ]öŠ=ž)²µa]ÎYj{Ö nÇ5ݺéH5Ý¯éø–M_ÊvãºvK«@¬ÍÕfµ!û8楺–êpÇá¨:9ª€ƒäxT”¤´–Ç!/åqÄ+ylóÇWåR¦¼‘ȹò–+™òÆ"olçµàʸŋõxjÊ`ºñò˜%$"YhJeÏñQŽ4¿¦#-Çñ‡®’À/K³#Z_VúôºXU¹džN³bµ”Jå%V…_íÍì ånâžOƒ¦¯L¨ rÄŽîy*#ýž _,1ût<5îÏç~Ä1o-P/º}©†ÊáQôTæÓf[¦yNOýíü'ú ~-ª*·ªïÏ®óö—*«¼t;ýË(Ö‚Ð|Õ†Q`U·ÑœîjPžjóqYÜŪï·ä;Tà¤A;zzp™Spö¶ó—i!ÄZ”·ÕÂSñ°ƒjžÃ³8ö «ØwâÒøüDè‹ö*¤ÎuºÌ‹°‘—•9-gâÃfXd -ª zÚámËFB®hýÞWÍHÈôõYä>Ž}àÀú8¶q„«æ‚UGA}fÖ¸ÜjЧ)--ro=Ž$^C$ÄàO)ÂE¡f “Œèð5½$:<¾É–ä@ö¤ð9³ÄWO š³¨ú‚XÑ,®¼¼Xß …M`}3”5õ¹23ó‹DæHdŽÜ™™ûÅœY ú9çñäzDÒGËOàM"ü=Äd28È­ÒTI¼olÊ{æ9÷§ÓþEð/&çCò“»ük6¯\9=øäøB‹¯÷d^Ê<ù'yîÁx\—|ޤroÛÅÞ Áó½âÍKušÁëF?Œøäï£Ú“ų¼ 3÷>nzžc[žåÈOUHñk:7M¾‹ÐÝV«¥@xÐ* v‚¡PSÉùô°ÓF‹hÂ×›ÓÝͽÿ8ZÙ‡Â|rsjnÛÈ4êÂ;Í’-6£mš%nÊâ?ºp‚í ³–j€?qËE5JÌC§£ÊÑ©âénn…â£Æ2žÌA›%`G'ðRH"ÀWL±eÙê„ñ‹*OPó‹?d.;“>­zºƒdb§G&[á~óF ²¼±GkÃ®ÅØX÷,÷|?EC›O'¾6µÏÜÉ@“C•î¢ £J¬•‘dÂcÞ¡êš'hh°L#ð>„÷HäŒe¾Æjb´8ÀK×›Æø¢Ã?±rg¢&åR¢vBgÖ¸©™pD½5vïÿù:&w«­kGÃU¾}\K¶±]-YH¶ßaÓUj€ŸŠ[†W㿱o@5N޾Sw*®žÛ{Ã{ o¯‡wÐëÂ\nÎØ”kB9Ò1 ¨®.M¢C§©Ì 1Ž(¸>ä®à™ eô±RK¹EAšååI·"ä¿f–šûTÆ2óõæž&xSBß…uzWy¥ë2y:™p”ë”çòžò\Tžc­þ´B…I[MO‘²{B‡ËºtE j³?‘ýŽïæÏ ~–{½q`cÞÙ]?Ñ•¶+ ;ôSßж,¥¡nÁuL„$·:¤¶%\„Õ¢=(+™†b½ÀÎy®|<•Š lt‘@)Œà\ònPþcK@µê›>ý&š]‘]]–wÔmÀ¹?¨ØvÍ @ Rì|Gß9æM> ´ ƒHê™ýÑA ²“„¡réÖéš×WE7D$8ÄHx„4»Ê„AŸ*#–Z‡ýa/Z·’éºÈ½÷dû ¹fkÙ3¾_[ ‡)cØïß©ñò˜m ¯õ0>óçFsq¥¹êì5Ö‡X+ø¾H¼…`=ã "éBdº4ù™g4™Í ñŠ<þ)ΰº7»6Üßµ'Þ³`xØñ¶ñŒëÁ»°ùÌÞ;ýÊÂA7iݰz¡ðoÿ¹ Fx s•cEê†tÒNÒFüO²ÿæýÎ4‰1QlŒ²™JlçÀŒ×ãpà.ÆYº\¯^ÐÕi*PïøÒ®¤&/Â.äŠ=*îQT‘"õûÿeð ¨ô t°!‡£Ž”ñZ/W‹ëbµÌAÛV!zÊØ*<@y÷>^E¦_°î5 šÝûO Í΃±›ÖZíÄßõX(˜W|Ý<Á÷ª6Ä¡;4Û›VCªE³ÝØÈýU•(÷‡Y|¤´ãª2Ä¥ëÓ¡ua!ë½WÅ_¾¾þç·×o?Þ|ÿú{{ûîÆûTù†«ªüÛë÷¿Þ,>üеvÞxÓyòd‹ù[Xà͇÷Ÿ_¿}ÿÉ{ ?ß½»yC5ø›÷éûÿ¼ùµþöÚxýŸ7ÞÏ77ï½_nþóæÝ‡¿ßüâýüO/ûøþÓgoNí½~ÿ‹wvóñ·×ñ^¾~ÿþæcÆw#*¢žA+o ÃŸ gTûô·ÏŸÿþüääÿøG÷÷o½é¾ùíäÿ+äÓ‡¿}þäïþöù÷wO»Þúæõ/ЛoñöÍÍû77¸vx¼ûÕÿñÞ}ôÞ¾‡§ß_kðÁ"ïD‘¯=ùQëÿã ¬‚_º{”6ö¯ÿ~ÐOµþÐúâïëÿK|„°¡‰¼ Œ¯§öMµF¨Ú»¬~‹Cm&ºˆnUâ«Uü…ø³f¡8§?õ})ía ï?ÈýŽÀVxc£ŒCRÅË èÚêi¶ËàA«õ4/Æëk3~uy™wý¬qÕÍcø_qCR«Ð ãòÑÁÚQ°.Ê ÍÖ»â,ë\ì¶Û±¸¥»¤b òeÚ¤™z"2е&çþȲ9:<4èŽÒߪáÇ1çäÚL¨Zô¯ñZ[ož{Y×›ó5EPšzg]ïå¸(²Jļ] Àzƒ7ïÁxβ"{Aä.·´•èy†úÅO»jÛɼFa(JyQâÓô¯²õÛ´³g%hõÀ_ˆt™üw ¿)ª^òGrŒ.s g!×䀶4Yç§S´À›Ì Qò¼ö¥¢sºZ]èÉØ`,ÝË®W0³íÖ¢OžWèx+±I¿þÂW9ÖUl¶ðVEhïz:ÊOÉ+^¸A,Àû6^>ZÆ4§ÊÆ‹r^&ßsì¼ÀI8óáp«ppâ#ó‹¿4ÿ¼€6¸éGn6qà{P6-ã¼ÙÅë"à©…Öd©‡I}”ªª^)ã‚xaIC^îдt- ¤rQtà z-vÐkQ¶HD@MˆÏQÜݧµVZ¿gæ&²ãSÑF‘„à­!x±ˆ³„ºÀârž»sÌøj¥n2 :×0£Ð¿¢«|(¢õ¨Ùºn„5­Ìð&w `ØàvR‰<éq0cE¿Ô¦8¶(!ê«—®rÓ]˹JDË¡sAµsÞÿÇQ–ï¹È9ò·TaEÄ{ ‹ñ¨s²A¹#–… 1²ÐÜz~°—Ž˜Äx^¯#wÚKc R+qäÙ¯ëS¬Ç{”Ãq¡eÍuÿÚk`lRŒ„,iG¿†~z8BgÔ8=<·Ç=‡E±¸æ;ô¡“Ss tÌS13A§e<Ø($vç—Sß,G™*Úã o†Q±-éä¼÷£wUfV2þ†ÕGûýØÌø”¸¶ôa(o+ر™+ÌŸ0QÈ:ÜÑB?´ëSâ‹ c0ЕNj¬8ƒ”¢dŠ9÷>Zì÷~Ô„¥Üb`¯ç܆‘Ÿ¬ª¢+®¥¿÷">îcìhœçƒöµ…€@5ºøà&'ϵ^îÚ¶±õ]k»,u\—ÕºTSEe‡¹-Ã@© a©“³ï§ölôÔÞÑ CœîꦻYÄ£­ÚÈÆ=_,Üð„Å¢GŒÖBŠÒ‘(GMDª®Aúœî–Ëk½÷¢QàîÁÖ[î@H¥ iã¤ÀƒIÀ®Q¬}Ü5'ÞTø•=çc9Õq]Ë¡ºÄ7\ƒænÌvë"ßÌ… YÍÁÓë§hi¦XëN]Tȳu>å‹y½§WOiÇq^¬©K^>ùSFÆ,ëjºæè)Žó©¤è€,#´*Ë9‹4Ÿ¢Fvò•§ÂÊŠ^jH†³ÙÝ]ÅXØ@ÁŠu9ïe¾Pa|…ñ{hÕ.Í.éBÔ2åNÁsOW“ôXØ ä)ÏàS¼îe=aÖû$ž§~5B·g4¦&}Å^€X?F¼ÚΉÂysšÁžkezïÇ„o!8ll™Áó~øá'sÆÊÚfHý6ˆs {6F5™ äsážT@BAŒ§¢/ ¿ó+´ÉE` 4ó–›&´Û*0TŠ¥ÌŽ83«ÜŽz%·öæÀ.f㵇UÍAêÓ¥ñGEŒ þ(‘‘j° PPÆäî¹A1$2ÐRA]÷” írjCLlƒ©Ó¥ÝâÃqVÀûË·–’ÀS2]S¨ßZÕxŸg­‡³|*$Ÿ6b„mgͳťä¥Éë0†)³ÔÛ¤èµr;‡´ø‚$;LCúuybNÈ [œ5øY*þ•Ž_y?¨ž¨ŸþDkˆLP„¾Òü²rEÈ.+в­šˆ›@ͪ=Že-m=ðìËÊG<÷É»k6„ES㈢ÍWùDóî«çÓhÄÐâÔ†ž¶)w)ñïSÚ¥„â^Úx;Ií¸¥U«ŒP¸—+ {£ÃŠ"DIî-ú~;E@ê1´€›@ÂáŸc;çÐy|VÝòTЉ›t|Ã+V*/ÉE§‹iˆMM/ךEE!Z*.ZÊáÑdèøë´ÍÕÂ$6a=$È-¶™¹h§„Œ zEâ›F‰*0&ÛÍŸ·Tes)[?›©j‹ P™U¾ÂHÐGUqIÕ!êcÕ"ÈFÕÕ¿ZP'æØ‘ƒŒ¤(<ÒVi‘\P@¢8ú쉤S¯‘åhÔDGjeo[ñ#ÚÙš=~úRsú0ÖÌ_]Ðó¼H”É´ klbm)Ça×"Ô8mMa£f î2›ðÕ7y…糪 Yޏ'í°éî­ÐÉŠ’ZN¡›ž° [€>S=ž)$½ÆDU¸ƒÔö±Íj‡àÐF¹‡=ˆz Û¯ˆÁì ª¶Éd'¼©tYŽ_i‚æ1YÕØ›æ¡+åÛëÊJaWl³1ή†ƒîEµç%|GÁÃéJõH¥ £uJ„|¡ï¨Ê]Æs ³&ÂëU,)o¸ ¤‚t•û9ÂôÎ!5 €¾MëØ_BúR[škMiÝ7Ë%yuªšâA)SÛ4W{ªëìrµÞ’Õ·ì(½¬^Ñãš­J.»s¨j™MàÙÁÝ+a†è’×ÍÉU€÷( ÓÅ£à=9¼æjôùhÃ…D”|÷½œ+i"‹ÁMÏ U–'ùêSõÄ×X¨G>Ó©"°pðKq–Q‹ÙÃ}'¾ÃÏ5c¨Ô(ÔÉG%ºóuæ9M®g¤Ž_‡†ÅKYÞqd”;CôÓ¯Q7yE kõ)tö «±†éì½—è§^øOÛ5zâ°*GÄîàC„œä·š/âgcEþÄY¤þû̯¶ì_7Ôp …KµXòmV~mxENxa^uÂÞ xޝdYTø†@EA²3¾+z¸Mvë­ì:ä¢rö¥ÇBÎó œcΩ™-õq iãª!.2RÚv6˜_‰û4D¾°Ä?- _ž ² ¾µÃÀè+@:sÓ•6MR+ÞØ*§œ_ð-j0Gâ¯F¶×ðm§¨fŽÒrŽRmŽ\xM2ÐáÞ Ýê‰ÌLš$Ëý[kW wS€<•e tåBF#m Õ.jÞ ]÷uæó"01=dÊvÇß; ¯@® 4ÛÇ~®?×­3xûê dÜ#¹2*.q§rû³øLW^Øã{Y(/d€g½y;KnVoß¡p€ ³vï¹µ{M3/IŠáú`P|#©å2ÈK(—4,‰61JàfvÜÝ­ÛœñGüíiüSgŸh7ÁÆ…FbûǹhEåWwª;íÄ)R‘F÷&VšónMƒžÉ}çñdŽÖ˜àëÕŽì ÿÁû•@/Ç›çÏü⸞µåeÊò&l£:ØRd Úür•^».¾ð£ëÎñYÀ8y¾KÜÐnɈïŇuxÒ%wðÅiŽØñ3×™B4Ðö›ÈôÚ)•šõ'{êFzÐÆJýÑHnºÇŽ’pSN T’w¹ùdžzKëú&vß‚¤¦sZ$¸–£¨Ã¾‹¦š§Âí¹|džòÈU½÷@ø‰Í<÷JáÃÕ›#ðÒ~vHÚöV¤5½ºÉ@Ò¼rÉ„#½—žou­W65EÎùHìkꙉѶ¥n‡ÍU¤Ú+ Œ(›Šˆ-=PËaÚ_én)$=XÔæ°¨[ÜR-2w!K+±ùl¿èh®SŽrèèo³ì0³OúVâ‡YbÄû Š.×¾ oXnÖ×’oË}Iv­‘vk#nž­G‘ŠI’]‡#L>2õS¯ÃvQ¦D#LÖSbL‰ô”Sb=%Å”DOéaJª¥\o0¥×.åiø–ð‰e6±]Bû™‚C®oØÝM»è”ÁVüç­=b¿¾÷’tZWÈ‘øõ jT5sC¸óQàìvþHýÎõŽç·í¹š¥—Ð1oÌ—Já2YM€¢"ÝõJ›´Ð…[_Xye©Ù¼ê -Ù¡kô`iÚAÛ]RÏ4Ÿ* ZÉF¬ÿœ`‘LõBÛP¯}.|î[ÀÝç¼q$|UZ|Ö¦}ºÙY‚¯Ä ŸVV’Ö=®›î|6ÙIò+=UÔ…[ÒOWš‰ƒ&G@2S‡Mq¥‘MqÓÛã»D¤êœºîïá.ˆ»øèQÁ‡å‘CUôèÛòÖ*ór€/‡סÿGþ…ðà"ñ/Rÿ¢ç_CyŸ23Yp€ +2Ð ‘A‡7xØlL GÂ…3Ë^íã)ú(Ü«[ú†³½­pŸZ¿½`g ]†ë¿/ø;¢ï˜¾úNé»×P7t–» 8§¬N7i’]yì=Œý;â†nÚ•ëCÛ dÎØ™8´1ûËË[ìKä ”Ýo_Bˆ•ùFíâíÛ)Ò¸ ™{Ñɪɴ|2]A“ Xi“ØŸ$þ$¥P#±Ÿ%~¿{~Ößsï¬7ŽBã¿È'ð7Á¿±?Náw ¿Süì­¢Y{µY{ üKýqÒúð܇ç>>÷öU¿Çþ4ñ§©?íùÓ¾œ  !x%5)Ú^9á—+¡bv(²|Ðí—×Jâ•ö!E™ÆûÒC-5R©’KÖEü–öj%þ³T*ïûPx ¬÷ˆêpFÝ[ŒµŽh-(ËI0–Ù…E'”šZŽ^ì壀p‹¤‡Xb(btñ®•7U;¸”ryA´d%”&.‹öʾë7mª;:ãå©®{æ)W;Z¤0©ØçžVGÝ–Pµî¾pDe2Ãtç«õt”z:žÏ•R‡W‰â4جŠç®ä+XÉ>`Þ¶V nO4åò–IÇMÀ‡b’ëÆLã–hqÍõÞ“¸eQçÕÏvïƒAŸÙÇ£r¬+b£°±.T#çìk9Wí°‹ä[së>äíÞPò˜±ä+{ÔÌ`O+óQC¬a¼~¶¤ †fbF°dè•~=´)¥a±; ¿½ëP]y?om]hWÙW„]ŠV +޵Šc«âÐe®¹ Ô¹uiW¯›Ä¢G,0l$ÑI*$ª‘D4¿âÖE\Û\"šKÜÍ¥Zsi¥¹T5—ªæRÑüJZ UÔ5œŠ†SýЯÖrOk¹‡‘„AâÐÛî©¶{ªížj»'Ú†_i ¤š²2ºfµO—s^Aˆu¢¯õ¨_E_õ§¯zÑW½è‹^À¯^ ä+èEpÚÙø¦´Ze]1œQ=íâÐb” 6ÙFîf¼›bPrŒ7ùˆE(+’¶tæ\´ÏA«j5¦r¼S9Ü©íT ¶ž€·§ íi_,„†#|áÄڅÉh1@Õ'¢‘Ée²C™ìP&¡ŸÉf3Ù¬ŠåT²Š^)©×ÇËs­†‚ð´-6„vXöš?› bï9ÅdÈ)þµº3ƒc`ãpq¡°hþµ4ª“Í…hÍ ¯Ø\TÓœbo“ÑÁ& [/d¤(fðã¤(….W .]8¢ -$Š‹^ܤïËü#*s‚d«…òâ“JÔª¸ÀP‘VJ—o‘ïb¬¡&KÔ™°Íš<±ÌÓ™ 9‡jìˆ"I¬©„üUõ4­È;¤ïRšIÙ*Ó ›Žˆ$ªP'D$F}¶…M©C˹+Kâ%v@ðèBÄ“Jxõs*3š”ÙŠ"Y™”Õ*@3WTÒ=ÉCª¤çZGžÞ“Q5ôzjbQä=ƒA¼Éè¢jv¼QºnÈ«Fòܤ… *¹±Ó¨>ûBg–Æ™œ¼Ø}E¦NN#­J§÷ne<ÊCˆ÷d8уa‚N¡€ˆUt0TQYÈ´O(i/ºó,a£Œ¯ã¹C b¹Æ|@¦"Ù§Ú Òà­AéÁo¬Ø7FWe‡•)çÀÝïT¼åè0O*Áa GÕÂ'4žÈŒs„‘qÇ|ñ1_öïfZ¡Ym}Þ9½9žŽJñ®>\”zoè:që…ºÏMŒ¦˜(µz¾æg‰—·±å¶$„ÁKB5¶#öþµ †²¿ð¯M…ÄKó×™1ö—¬í@x°¶£T#ý5CRu¡d™PµM“Âív¾³É*8ZÑÊŒVogËs¹¾J£Í¦¹ *2”w™­‘nwÂ3finÌHÉÄ¡mŠ&@‰¬†å”l‚³Ð0›Šv…Š®6 ÒEñêX±uå¡ìG¶Ž ô=Ó[` d–­àW»Ñ 0Ü šm¯áz·D8öH?¾=}–©ãüjžÌ%dÍ«pÔ)ÌDo š·ZÈ0€!Ël”´Ç?©Þ¦ Te«a4’Æ8Êá Äœ©5D¨®W¬ ó°ŒÜ¢e‹žJ÷\ÿÃQƒqþ„ªÈÐÖé Ž¡¹g ß#¬…Ð\È‘ì%!+©øHUÙ1ߊ7y›W>„“Èíâ­ñ…û…q;9ŠÐí$”¥£_¯¼¦xa(ÁO_`ƒ© ±ñžÝdšƒ‡Ws@‰êœk­ ë~uL».lµ‘ÐÆln`{ÊÞbw,ª®%žZ¨¬íœZ¢ÕˆœhÝÍZP'9¹ÕšËY—ÜvÃáQbÏêµµ;i/*àËt3“Á’E‘-F¼épnžÈŸÍô¬ì™Ö¡ßŠLåmÌ.‰¤RÍ6e£ bÚ– !§D--­U¥2”)n1)᤽ÑBù·Bç_ÕÏðE=t—}!@õþ; °4îÙ°Àœ£Å´IdÉ›Äð— <ÊÇt4@‰~XîêÂôÀTŽbÌ“h[¿0·£a%1 GIB©©ž:i“C#9Å‘Ýv ‹f÷)½—öBýT¥q<‰ÂA_zI’ \Å(R…ýHoªކAˆµœÄao ¿–â4¥7±ž’^Ÿ;F‰Þ^2Ja¿§'§0ô0 ð…ƒ^ª¿ëX¹A¢'Ç£4 1†a¨·ÞOFaDÂa¤§§8@ÇI¯oÖÕ…¤°é©Y8êSbÚïúÙÊxÔáa¯7Ôf*KDhWÏí†}˜†¼Ó_öF‘€“^SDÑ©k”LcÊGxÉ|¼¼DR„ëGØ›†P:ê‡Ð4è3$Âhƒ(‰5ˆLãÑ ŸÀÿýaŸ!Gð# ƒþPC€) Fô†A¿EuƒA'ý ¯×–Žú.ã("ÛpÓ {F³=¨/IãAÚ”oE½4$ð§ýQo8ö‡´BN¢a<’H›æ v\–ñ??üòúÓ#…ÿÜÿ3ÄÐ~aÿ3Ž0þgü=þç—ù0zèG|VÓñFìUäÖ1ŸZ&ylÐóñÄós¼k|¹ ï~Og ›ãWm¹åxåðzò傾wø]›ý^ÁF¿dQ¾ ”7#˜ãxq–®ÇùDÞçŽ6z0ÂèòúÇ5#ŠæÌÃ/Ò¤5^· Ó?¹Ðnà‘Cãf¢.~-#…WN«º'ÝYWÞÄ»Á‹­ûëíEÞ¿‡ u† $Sö¸Ú¡‡B‚Ó¯WP†Í»Òs íôZöŽBµ2V¨VÅmƒzaâ;ŠÊ¡ÀéB_nˆH¤˜ØS퉿Z”ÐÕd»Â+R¢Åí•7Y~“1BØÁ—‰âº¥eXËè‹…¥ Ÿ{tj+ްŒ¹š³ü¡oœ8 ì]À&ºï¹€”ãÀSÂ"}ÊÇn»*VËÕnSÓ{ª!T5`K®¾"ÀŽQ‰ã~×»FÌ<60eçÊ¡5Ù †›aåEÓeŸæŽ>Yûë•kŒ=¯¼ñL[Ý|¢\Ô±]µñ"TWø9ŸekÐb峦/oÆÛ‡:ö–.ò‘>­VS–0ã«ÞŬÃTËÕz;.ôð?íòÉÅÂk“‚klèJârè|ݤخe°Æ6ÜùNO»?÷{ÜÏïq?Ýq?QΔ·ÍñÕTÂpç ($®¥VnsoJÂ΋pá•å²Ä…c Z6ZÔ9 ? Bâ•ýÐëQøWæÓµ`?eØ&ŒÉ‹åçuÂtÇUïóâÕª¸ChP¨Ip©éìÚ_à×]™”mPµ¡D!CèßÂû Y¨°@«ÅjYtÊ»öÔÅ/¾;®§Œ):U·ÀŽ~E§!Pw)¯¯Cp¬Nó1E=ÄÉ[mȃÇ=žÓŒö;Tô%^Á:ª™ j†³£f—$÷¡–ûç¸ÿ/˜áº:Q×èª^-ŽϯŒ c™xŸÁ阢<‹šðŠ{F$:_3Ëùø %ÊÎË·7 ¬sÞ&ͱ¢F¤5¢`G-1}ÞôÑ×I3´Öž@RÞtSwALk†¼¹f>iä,Žwòõ5öª~jÇ´¬¡ª¼´ŸWQÄ5·–n Bd7HÄDo¶ëÝd»[gGÂ…jfWÆŒñ %®ó+x Ë,W´=õj‰¥«èpÞÙx·Ùt²E¾ Œâ"¸k ~Q‡~€ñXsÉr^b° #n›êomŸDÛõ`(sRT/‰À›½¬Ëw&ã4 %œù`öêzXßG«VçÆ§+Aè+¨E§[’í(N  6%¦¸ìötVJØ_…Ù^Ý…ÙB¯G!Çå#½Â%nï ¸­ó]¬*@q‘u'0Wž‰Ûƒ0`hQª‰WwׯêÅ«F-Ç•äT›öÃät:;™^ÕÑR‚ßsÎó„ª?šVh]©¡¢­Ä64PðDÍDÉ¡&ÑNÉs;†q¬Î¼e6.@ÄØxªhǬFñ)”܈¥Î!Ë庺|j½zÑ4Ÿ{elR~na¾Àr ÍÖ‰C8æQ ÐZäE¢¿Ùì–ìÉ|ʘ£²Ÿo]’­(† ãHŠHv¸¤ Íû­WãxÙ ‚ukÞ+ù·mI(…J4¡”f³œŽ}Â×x£3hàÍõ«Œú#$KþáÎZÊ‘eRäÃ…Ü)’ aØR*äîi`¹0œ¶+ juÔŠÐä KÚ?ËùõûÓŽ¡J„ªÏ)Õ‰“.Еc¸F±.ïÒÍý‹õįî­ýTüÞJl”‘âkŠuÁ"=5íÒè²1½ÐŸ^?•:‹uǘ>å•üÞS!­3a¼1Ìönƒçi76•u9×ÀSñSIa °(µÊrÎbÒ§¸cö‚B…•q»ªÁüI0{ Ùß` "ï‡ÀçMyáѱ‘~ý{­UúƒØ Ó⡳ƒÌsCþÔ?ba ÔœŒ) R­+¬zÅQŽ—þFÙÿI²¡r\ÞÎÉf]£Êsõ˜ýã?zžØŠv¿Qëws~øáGIV@µ³õ§&\ûÎQ°#5b'ï4xb“©R €n¾Ú-¦À8•.Y”sBsE:÷H1šQ'Ë…znÐ-S"ÙS.´Ë©S.2\©(L7n‹™ct˜ˆ(Æ·¡–»*OÉ#ã©“Øò’o¬ÂØ$ž[“[4¤x!£œdÎmÑS`àQ0q‹l¼©ÄWµ>E«üºL°½ÈÂv˜4ÛQàݬ΀˶ šÊ¦â5H¼’–ž Ky©„´‚–uüuIy®«†q¹Y~jZ"Y·Ò[÷©EXž‘…ÆZ7DÌB¥Hï)D"ËDu£¬©: íþÝ~ Ž¨eNAÝ 8ÕO^¦´óÊ6$B™ŠÙ]ß(pj͆ŠÇDD¨^ƒg©)”0àŽIתrÜ)ŸoêÍ ´¨G^Ô*Z¬øŠªA–´|Ÿõ°9Z†?ì_—%(×.»FÑY†ÍVC®Å} QB›Ùœ÷̑ޠç!A*©2QÐV‡ùÖ!"“v£l¥ã ™³©ú‰ißSIß$A× ‰(Ö{ˆc^Kå» L=15²“ZƒõÌ­^j~!€1c¥ì®æˆƒ¾le€6ŽºÐ,×…SÕ’Ë宑žØÙi¶}‰Ñv)@w•Hm©¡×"šè|昬qBú,9Ö¦Ë?wwî³ý”vs9Ï7[ªÛ"ˆ$F–RPÒ ~ÇùªÏY3L,!.ÄÚS§»‚µ¯åø"CEƒ¦Û®èe¶X°3„ôW‘z:E§E&_xN*äyq†4j£&ª ¥£™7[¯–¤:ð“¢J.]šËÇd¾5rcÆŽÞ<7Ctãa,éÒ¸u£œY½”af+­ ²àŽƒÊ8è™ÒŠ㫘½Ù!FMHy¦ÃnWE:zÒó’}®V« ¦ˆr’F˜[…#/›5ˆ@2ò¤««&öŒ¨÷] ,p ÇéxR‰÷‚02CÉÃch16Á¨EÚ‚’”UÌhªÛ±ÝjÚ•±ÑHø¥â%3 …ãÙf³ªrr«"XnŠë¾ºÂñ"êÌEÀ{r“6:qä_û ÃË3`¼ð·½D$äèöxsb_†¥€&r B°„Å6¿\n.#Tâ€nÐQ ›;C{ríÌÖÛ|YòAA 1lЃkŒ¯5Í:öUŒµM˜!L‡ÖöòÀ‚&£Ub-}MŒÀXÔ ÷Rp–Ù‡‹Ú ­]Ê6½ÒI# »ž’d–xJ׬ùÆ ­@¤ˆFšÚ«$q„'~¢”ÚÜÖWEé>¡žY–¤˜JÀƲ ûÕ›ebDXï£â:$¹"{i]·4Ç£Pˆñ糈F’mÕØ¡¥«®_-¦øP£0Yꌧ$G<&­†4¢Ó½úxÓ¦è´á5/´HxUÝ ’ÍÒ¤ɇQ{K§qäV›‰:-W¾ÐeÈ3¥L™Õ5 ø¼a§mÕ‰ðhijÂ÷"~(CS¨Ž `±2)Œ”º€.ZSÆœi®Œ«ë C ã™Ö=ºd}w¹*D?kNàõ’|;GéIUVâÞéãB‘,ÔÕÒP›PB„'kˆ[²Qå)+q¾$öMc-¶{ZïDxëmBt“'m&àÍûÊÄžb¾gåwy]éž’‰§±w†&ࢠ;;è‡$‚¦!©(ĦÒB îêÊÅ™šÆIµÇ\g›,ËUä@ºº”€·øO›ÓDpMÂã³ì*lô'Ëq«“œÈ®Ñ¶´p ÞçÅuSo±×alŒË[æÐH¢çï7eÔ=¿úFþæ§zõüêú`¾Ïµ1Ý‘¦#ÎæumÖn]7¨³\e,´\ziÃXïò=,/viFûxan%E¥{‹^Säø”†;«õËñzÚ9O.ð«Õùv'ã³Ý™®"¢ì î¶'JœüØ!ïRXmw½¥ÕŽÒG°äسÂL("ºy/œŒç7Þm‹%z[^.&[ÿe'Ÿ"¨úH¶å•Z„?_3G[0¿ý)Ycí8PœËÒ•îò>~C=ò…Öê‘¢K©':^ `&µ|x`L^ËÁ!iÅÍ×Z$X¢¾¾¡É•XËËÙ·˜`Ð!…Çוm›ž°¶[A%l à转@¿ªo8ÄÖ¾ Ž/bîÑ5Õ/×+òÙ!~#¯Ïüj•å˜o¶¾C¦MϫܳCð!«§ ˆÈ Ì«î“2a@¯dY|a€WÈÒÃYÖMöÄŒœ®¬§Ïüj w ®Ï«žç·!S$·Ðê/–Þvß»®d×» 6Š*VAu¼UEª22%)]E® ÈEÊh´¡¸Í€zzT¦Ûð^xš«¨ü¶á cÞ™· ÕÏYiúÐC˜º%™aꧬ Ö§p’PÊp+1ÝÌ®‘,áÞ6gü1ä«pÔêKºé^†$Ì9‰"‡kaó+ºâ5:’H;Ó£Õ"¸¾Éöö€üŸåÛ/Û}æ?Üú·µK HQè*MV@ ¢÷æš´[ç8QؘÞ¡¬š‹ë:‡õŽôK‘Œ®Ñ[:ï-j©Ü²§µ‘ìiCD@íi77WZŠ´–’š–<Œ2Î@Uˆ2X—%8î ­__<&?iJ4‘ñ¿“[ ‹& ‘bMïŽÒ°µA ýœáçÖÇ¡@œÀ£×¢}‰ì o˜qxs2‹’hÝ^ˆj¢ ±ôþ «ãMæÙ䂌gê=‰ä«îEW’uÍ·Ö0E åËéy°<Òu™bš "Z³'¯ÎÄacü*³#J“|f•r×°yÑíte‡2FWG7‚ú14€çûÏšû‡R;{<2aº²gô~ʆ4‚œH€¶ã­1w®œð«¼ÐÃWzˆ/÷’PÕÕï?¤8LjÁOá®iê † BÛ6†Hɤ6ðv Ò¤bêÃq†m½zYª‰J~Œ:ìå‚E©Mý—ŽˆWžÆp¨]‹Ê.¦Ÿ>ýe&^Q6·øÉ»K­Õc&q3VR¦%h Ü0@—ˆÎÀt®bÞ=bsÒÆòÅ´âÖgåÀj>îUâåç«S+À–û:j‘վͺºªe¹›”Ê Ó*©P1<õãx|ï)a§0ˆQ|#ðv‚cZ¢ä¹“)8‡Éß­ú ïF£®˜DåÔ‘áXCªNg´w*(KXÛ¼þ@slƒÐ§íæ6Á–ö×€,]³ÿFùîˆ5 ܞܥ å8»ÆHV‘Ò²é5h#”Ú.´Ä½Ñ’Æ!¥I ¶à #-¦´ÈHK(-6ÒRJKŒ´¥¥ZÚìÊ£´ž–ªÕßhIH èE;i•©8…ô®]´tr“g è}–F‹@\¢þvµ%ñºêKªµdUäàue¢¦¬Sj` ~‹φ"qt'/6;©D¨¦¥œã£Ëk—]2Qo¦ZËzŽÐ¿Q< Qt÷LvÍ4ñ$¿Ô°D2¿ÄQÖŒ0?jˆ]ct¹>¼üÎãý–¯fÀ gè2³š€ÄˆŽâ–6Qøj)ÞÐxU^¹ÜÈæ¹ï×,ºìoWÆqP§b`x*ÂPÖõjYí Zá`î[÷O¢µn™”N0Hû¾IûBIýÞHÇ!++œhÄñ‘6ùJ³óQ2÷]vIÔ|ZIZE€óL¤"Å™š4åí·ú d£©U¢R#-G¬ýN´ß©ö»ç¨ev¥2 Ÿ‘¿3õ )ª0?!R;ªR¢§’½ ò2Nš4}²rú2’0Y@}4oúhÖ¬ÆT7ÓL=¦ÐÈ“ÜàZä#µ!‚›Éƒ¦'h&!ºd$FV¼Z˜&}¹Lªë¸}›Q\ÏÈ¡tÈþéá0j.­Z×Ýê÷[±n·„›‘k9¨Õàã*ðûáŸØÿ"øÿþ¥ð¯‡7^̰xæÏèʅ˲":üUŽñ>ø·¾ÚJWÂáA>ñ^3‘ï˜ä>êG”·ä3cº©õ^Ò]Àí­¡ûÔ*–ÉùÁŒÓ=`ÑoÊûFôÀ%ZÀÍ."NŽùOÂRþÓS—™øÖ¶QYbLƒÑ²e D9TS‡Œ|ô|(Œ ~I‘(!ä— ,/¥Q±QÅ;—î•€nú~.:Y॒'ËE‹þÒ:==õ—xb¿g3xÆ£D*€&œÐáÁ9.Ù¢8¼Ç%Íæ›±Ü²Ü§—{ʺ\£¢ü"%BE<ŠÕÓb=¡xYJU2>†îÕEbÄ :¥-&gM÷$yî È™ ð :Ö/¡µöîŒC†’Æd•Ѷ‡(2‰ñ_äO È$Á¿±?"(2IñwâOz¡Q¬¯z𪇯Rÿl¼\Ž}9cPD" …Vja:¼ˆàMÙ¢2a¼ Ì i1¤Å©G׊Ô!cƒEì}p,Ò»ð«JuŽÃ¬qÐ54õúlW!Ù€3#rƒµqΥǖãpqU³˜@q^ÖÖ$¶V¨`Õpˆœn†4–X \ ƒˆRTÍøÚÔCZ®• wÓЈ^HIQ5)®&%F’s/îRºâvÈ pãYøÏK~dšM°³LM* 66éi;HÛYi§{,Oðö´Ö^³ä-2x—Ùof3ù¦C%]*»#n¹ÌÆ^ „î!™3âÆïu®ß•@Ù+·Âï …îŒª€×ú¤Âš¯.·ú@ì€éõñ´°¤‚/¶Ð¸jÏ1Ð#mHtÈîŋw%hûÈ^5æî™'¤S3=À¬ö\Óx”;†Ýï.½«*¹là—ÂhòÅ(ô•A¨ NbÈóÄKæ¦LÀ‚ÁiYšÆl¯^®£zfÂ0ŠÑ"½U×*®;¢™,3æîÎtå-—x ]8’§À@Ù@yvØžÛF+s˜Ø9³BLeYÛD9«D<Ž·ÔÈ9#Ëe[uÕ“¿aï|lØ‘Á“4³ˆsÚl ¾hvPp_4›'A· ¤îjÓ„q†Œ.L ¦É]`š–0MK˜¦r\ð3i¡¡ýðÞ ¶h®'Ц8U[ø[yúµÁœ"˜qÓ‰`6wMÊpzêp¡µSrx^øo÷5ò2ÊøÁö-ð= À=mzi‹›v'ž‡´Yê}홡}@2èœ:ç{pVOK¯vZèP~µ¥õº4#¥ö›£Ö½ÑaZEËNÉy5Õl9·m“_´‹"jަЇ¶§‘šöi¤Vü42W¼m… &†ØÄÐHÉw¦qÙH\6j$®6rkUñùxa¶ÙÊ{=<²Eç°è»Ú3'Õ†JÝVɹ„|#-”quUîwö¼ÍÅHøF·…C4©‰*ò Cu}±âJ'+ÊEEù±Yþ’8"ø×nðr8Ù\4[­Èµ&0'©·ðã¤hJ¢R;ðȼxóR¹yÝ臦ÿaÔ“FbÔ½°Ëä_€¶1ò6ÀÚ¡A7JA-cˉ”èÑko~2ON=n„²Ï,9YÃpðjZï?ŽÂœI(LÛZ¥œ‡FƼïCœÕ–¯8(7+LÔÀÝaU„.ç¸ì ïêR×]“Oû ÔµpûÖœ ø¨1‡Œ'óf GS{ Å„qMÙêôð‹ª-K›L™ÇÎRN_Åa8ðBN蟱 Dȇ‰lR ¦ÈG<©Gk7]½Öè 5òä>•Vòj¼ÙZãõÛ\u{‚²EÛEÚ6·êþ˜c‡ìþ{dÞÞm²ƒe^újW}àEÅv/¡o/µ(É,ÂÛ½f6µgLît¼y¦¥[Äí’!)RÏÜiIÊJ#—\ÊêL»£nËgÚ±íhP_£xÜRžæ?:a ®é$WYä½¥×þ »Ýômì`Q 6–ª9*÷Þç°ÜS-”|udŽa‰žqgȯ4»Ê·O°bÍ8Çy¥—ë°?lâM V2‚Ù{¹ƒïåÙ=_³µ_ ¡úÌ»ša¿§ÆËS_Û@ÞE€yæÏæâJsƒ»uÅ×ý|vÚ!g»g|X›.9 ›4žyFó‘Ù<ƒ¡Ëœ.UU—}`׆û»öÄb¾N¼ñŒëÁ È% /Kneá ›4^X(1Sù-ªK6ÔMíWåMíákGWU•­Tn•µn¾çë‹Â¸ˆŒÓ(pžŽ–Yºîuñê.íîxQ´öùý÷Å_uï7v1wð½+ƒ8ð§™’TA,¸ê`Zódî©8“#¡{´agÓloZ ©4Û”T&´"Sæ‡ÌêU\ ×YÑ Ý÷õîZwòϺ‹wÖѾY·E"³Ð|¼ ¡ üJpp oăžæ~4A¤(œ%§š ?R/Ö2fÛè”â°o&ǔ܋S39Áä8‰Z½Óp䡟i[Ý u‚n$qmŽëƒ8­Í‘`q/ÒÞGñ´( (A•¤IbURf‰)Ë0éõúƒ4ƒ0D=½@(NÚ°7 q4HŒ, ÕÇa2ˆÒpÐzPYh4”p-ƒa/Œ’ L‡ý( ¬,4æápÐKÂa‡ýþ¦Ao(åEüŸ¤Á0ŠzÙ¨%¥†zV‘$ƒ0 zÑÐÌÂÀÒ¸ â8ÆQ0À†Êk R‚noЇÒAÜ ƒt0L øã®dI{½Á º¸OY"œæa§=hlÐOÍ,„ bÖpŒ‡ÐñÔh( [úq ¡#aÆ}+ Õ2L‡IÚ‹` âÔl K %ý ô`¦˜Šž>è C·Ÿ {I“{ý^Ò7jIæFIoè&½zeÖB Å0Ã!ào4áojfIhBÿþðCW#KúCS}Y¦Qdô¥G}éas³ÐK .3 ÷ŠÆ%€·ý$î‡fCÜ—^ã …!E0r.½”@?Q<Ä äÔ":X·êAÐ)>#pF½Ö6Ô”¤£5 •4¬dÐÓA¿ÈöŒYJJÂ9tÉLaq&}³–„3Œú}€sºnÖ’r_"ħ~0d6@ÀV#H=€^le¡îð¹#_¤@ö-š/˜3t3…I€îö€l¹ØBê‚fŸ‹ S]‚lá ¨˜“7ûÛÛ7ooÞþäýíÃG¡Ñÿãíçß¼¹ùè%”üîíû›×½¿¿þøúçïÞ¾ñþþñÃÏïn~ÿuœÝ|üÅÛ|¾,?¿~ó( °¾P%‰Ë)÷xÎ'ü_Àƒâî/»I§Œü_’ãˆßÀfÞÄ-ø¿ñ&>éAeªì$‚ŸÍ“=˜nX÷æAV[5Aü¬ÐÕ ƒK9T3‡àA±ÙŠ‹•-$@v`’MA^PÉa JJ« µÂšw¨&@·@ðë¡nƒ˜oÖÂT2 ¢ð l*F¿þŽ©štH`…Ž @"©´o.õ± ’ k%)HЈõ€ú¶j‚‹¯XƒÂ2xÓVM:,i‚oXçCS`ª ,q/  ÀÊ Æ+xPøÿoïI{[G’›Ïó+È%J)Ù~ö'¡%Ú¢ÊKI>äà Ùd$` ??uô}H²ßÛM˜€-‰ìnVWWWWWUWv5óâ) rÌ™«üfr û‚Ipkë1LQœ^°É­å{6â,t¥gØöÁê`³ã©XxmX „ë¹³5ÁVn¯`Œa=p@\^á'À¸€×Nqsâ®A¼ÛEñ aáÖÄt#pƒëÊçEÌq`ˆÆc\«`¬ÀÖ˜Q[ èùÄÞ] X€€;Þ`·AJ´‹0,×°ò¢øŽËÝõõ]„aÅòëøD}Äñ­½“â5°hUÿy³ðÏΦf=Ò. 3l»®ì5WÚ‘QÁŠ“hüÚÙQLx?½œLÆ$îÎ5[b`Ò9RÃ-à7´éûßà/¹Ø‘¡h¨™}{c·"V— HÞ —ŽQ{&»÷ë¤yØ´Á‚»†[gcüÂÆW;ØpÁT(,r«KŽ{'Xæq]†±9Ù<5ÝŸ×ÿÇë×_þý¿ûÃå÷çÿøÝþõ/ò¤tÖé#ë6Ö@X7?äÀEAØ)€µÿ0Îa›rýC2þ‹@ã\þãŸ@äI~Øÿú_ÿùËãåN=3Z}þ?¹x› cëú~q%;¸DÜ$윈–ÃpçŠÂt‹ÇCÞYs†÷¼è†°"ZˆÂçP\ g’qÌ0jÏ›ùw±Jò“ct¼d·o(W¢•¬Z?Ö÷]Õ¨ÔÚ"?F§€çcŠ»íæM[uove1°öö¥|èÁ°©ì[2I†•ÝwÕÓvM…‡ðÊm×쌩‡æ2Î ü£ÌÙÖU·~ÓÆ $ŽNe«#‹™AXØÄtŠ/Ø4Õ Ñª4Ñíî’z”,ª¦£àöóäq”¼Tm[wnDøCÛ<×Ý#Íë䱯$Ř"äi?›  FóÛo~ΠÙb˜y.j%Å4£œsÿPw늬”vñz¸©šõ|ùÃïÿø§Ñ‚8äßÿç/úuôçßÿû¿ýnôÏ¿ÆâÕã.é×_þð/£—_~ÿûS•šv¶>ìQXN÷oZªQ²ãl—äÓ,PuøŒ£ö˜Àî3ÏdÌèzNüñæµzŸø$ªaïÐûŠ(Oƾ2_@>_³m×É\PiyŽ˜çTøVgùp³ÅÅr¨fÂam„•ažåªy‘¢‚+b`˜ž eŸR/4¯fä‰èôšTé{˜D²€›vnu~ðÁ¦¸<;%T£H,½XÚä 뎡€˜ö³P[#Í,§Â¬×ÛÄ¥1PL~Ïc©Î)ÿÀåI~ª)Y2âç•‚>ˆ@£è©…\µ€iS¹ |14€™£¬F~ôóÜÈ"ßM0;,Ã)‚ÈõàM7VëìÝ)F¥Î¡6d:WNnÜc¤ÖtüNôÀ¤ùø#¼w÷›8^5N|Í 8Fœh– mLJö»‡çZ2¢Ê/iÆI°a‰Á£B‹_&²³Çív¢æyœmU¤§YN«Ô¶Ã¬–FÙßšÙ*˜,¥šWO{  øÓ]ï5&¹”ë6`Žíøáµ±„)™¿×k>áHÜúž–{éMªƒùrÆÝ,Âaå~‹ë)È F©éÈñŒo/E®æÖH!Í0Ðe$SEøøI4´Çlwü«<¹ PBcÀã ´ªë§]†9¿ë7ÆÜz‹rcÀOZ'.tkäINoï+äÂ9‚,uÈ@ "MHÿiVŒô¬D$õ¡+ÀÁ‰ék¦ËÙ±…oy á¡ _D3L¦ÝiÆî« ÑX¦JO¸ãŒƒè ÊÉãP*/ó߈”†¡ IrXsÈ&ª?æ»§øNÔ|¦’ Ê&(]9g?]£U(I}b­Rúœ÷üá-[ã¿.V˜j”ˆ­YX Ï`ݘ}"TYÕz»i‡:•ºŠ+‹Ì,„•C×6»;é1)ùÌgzöh ØpDÖF•+=DW0"c@™iqÔ¡×Iê”ÆšŸcöt‚ÙHêØ}µÂX¥*‡l ;'_GzI«+àmªG@‡/Í®>Ù135í‰.LÚ` nâðx\›˜4CsíÎB’JãE¹ÞZZT°pmŽŒ'õœ¥wX2sŽQHhNàk«`®ÊSûÎ#Äu#P­©«QÂgƒ(­3aŸ‡Ý¥bŠyO™çÓÆ6б‹ÁÊsÌ(h„&†Â!ù±:ìvÃzÝl@ÃQ‹àEgû½³³ëšiB™W(x£0‰w÷~.TN(sÂ6v«xwtéJDF(œÀ¢‚A¡DÓ¢œ™”Ô0Ià­pÕýV0z¯êñ<¿lÞh% TkŠ8ø>ª‹xqÁ¨ÛG•È;QU‡v3’/Œø„¸vֲߛ ÞL²¯qó<úšÞ%:&¾RõáüíD ¡P¼6¶pjãìüÜÆñW Êë,RsMùÐnàƒ¹ °óÌ•…yŠÐx–4€<Û¬Údk/dàòjÓ£Š1ž«õ?Æÿ¬ÔÉ©M#qò‘ŧڙ xÓ*ήäÊYpMììɆÀ*ú}ÅhêåÌZõÄîݬÅV>"÷;ÎÉ줣>Aå|q뙤´s–7"Õ;kHÍ%Î\ÐtÏ\ÐN÷X$u¾ãa Í®¿örF¹®EæìørVG™ðYȸ P Óä•Ä\þôàùËŸ9øÿk+B°Ÿ‡cýßržâEÕ>êL4 ëqœñü«¾ùCØüm=IñJ£†`kÁÀÓ¡%Ð/˜.@\6›”¤QåHäu0¾É?òTø':Ÿ«f]!Áî¤ Œ(³<ª–'÷â³ççŸN¸Ûõ+;{â¡òü§Ÿ~ Tgåšqb/~V/¤—=vzˆ‘&+v¡Ó÷Z„.¶‡õÖi¥2óðgJŠ=‘”<¶“—ˆ ÞY¬Ñ–zŽÔËÝzêD%Ý‘ªÅmÒDëdÝa7X$“0‹&(ë’¸8{ o"¹r­ú¾ ëýEpA๎¬Ê3Ú÷¤]¥fC­|ˆwð+x•€…†{]W»Hñjû=Îц"ðºÎ«Íàk:˜öá³ï¢ßvˆ’ ‘Ö1•Ô+ ¨ÝïA;“ô²`ÃzÂm‰¸×©m.óZ‰*Ìx3mßÓ›ì¤Gò¦ÜúG–™µA\·ñS+c“ê'›ßfäM$ü{ÐòžàH¿ƒ,Ó3ˆ"Ô×X½Äu‰’ÈŒ.²ëe¤é:wá{ÿ@Eß‚Øå¡à8WŒ>K/ 4âWäd T“EBÕ(bVÛÌþÈjÈvš<žÊØTr5Ööœ9²Ø:b¢ $¨Tl AšA1›@º³fWá%œŽ öÆÀ úí G,¢ß2“È'“ˆiMDìr“ÿ<æP"ïãT’K1sêa¶ì´ß“<ë=ìJŽmPš½L‰I^]4_ûÐh|ó€(uX¿«ŸÖÀ©IaŒ`éõpm,œ¹¦ž'ÚÌÂËÅ…\ä"jT2ó¶…ד&º Èg~ÄcK™„Øx{âÆÙp~lTL¾vÃÛýÆtêtÎ\˜ A'D|~4„ÍæÐ¾ä‰ûzÿR½mcÁVÙÐ10¡±&m«ØQhia7b‡–ûÐ9þtj÷ú´hv^M ”“þªd(tÏsÓS×Å"ÌâåŠ!›1e<´¼»ÞT«÷‘4ÒnC/õzÍÆ~é!÷ñh@‹ìæÙh$O<öŽrLŒl'³“QñFdºÖ¾WÉC·ÝÎÁ#brRFÛ’áÖ0[l·;–´ê°Þ ‡“;Iò…ãÉS bd´A(ÕíÜt Ö%8-  v›»º…™ÿH{î‘rM$«Ù #»øÆçjþ\µ7'ØÊg*§„ еNzH ¸ 5+¶iݽ,ò²Ñ ¦? -ëc¬œ‚^+Ž`®m_H'X?ù _ðV=2 ÈìÐx‰izvINÎÆÎ«'i¢_yدœÁöeÓî$ï¶|A="ÞãNnt‰¤ðqn¬çH6¼^)ÅžµTõhâôˆÛU¡j/,¸h²Œ¾‘ÓÙçüFŠ”‘M³ëìk–Y~ÓlRdÓ¯Y@¥ï´QpÑ®§g42±¹‚†n ©Û,ŸQ{j‚`ÕÍs¬îܱ›ÊS? õW©‘›Àjs?¯.\'Õß ‹Ù®Á}<3oÒ·ÓÔÉ£À‘o(]š…- ÈE¼&¥E²b « %w¥u΄ÄCßNJdsgJ÷”ì“ßË7yÒ‚¢¬ñÞ Ýw¸{[÷…<Š4¦“¶põÄt«DÑOõŒ]ï¤U`¿¨œþ ‹ÑÀ|0¥3tЇ}ÙäZåH|p»VÖûæiMBΦ@í¬Ì;tÃ×=¢ZùÞÖÀw7z* i¡š-X ­ËI£&…Q–Sx0ýêÑãˆQ(Üt…7¸à›O_Êç,yþR>öž²g¶Y¬|¢æž‰|TS†û›vŸm/¡ghÏ tnÑMz_†žh0—wÛ2»x.¼¤ ÖË©´k­ å¹c§)âkø•„€fXäž–ö3ˆZlXõLZú°ÎvõŠœê1oéØRúqØà)b›p¸áÍ2åŽðVØkG,¯=$ÉÈ0é'›MÚÂz^5ƒ¥o90—ŠCmoˆ%ø~]•ãlc(j‡¼]¾“;oèñœÃ‘±õ3Ãx h³½Þ¶{)ÎI©ƒbÍ0E6ùçà"²É¸“áFd–9Ìól¹¤HñÄ´åÍcºî>0@ì‡Ù ›Ʀh×´¨Í•‘ðXê:î‚)Œ·V»;­:ß)"¤Ÿ ¼wôQ§6r©÷—s’®y\ìå ¬·³UÀwÖà€8-™iñ€~°»&ŸÂüEz-þ¾™†ßÂYÆòIÚ„ ŒÍáæ ¼¿·1]v樉$há×¼ÖÜ&ʺ¾Ss{sbB“Öq¦‹iÕ—Q8Í)A@„§B°Î1Z4LÂ4LIçVìÔÀw¢„°Mî‰_9G¦5*f…¢42j_(3@SMúŠR¡mö™ªŠNóùµ]—¤É”T¯ëðI»é ç .¡$47Ú<ì1ÑÑ1mlð蛟‹2æq5ü^è͘—‰CRë ûøX›æ²pu5£ó¼>`e†{ gä¼åε3Ñê6ÂÎ?¨9·êZ]K®sb!FÅW+Î9j-ˆ ml¬Iès\™f¬rÅŠŸt=oóBÁ¥Ñ3Vð=&HLxpÁi…c¸†'´F&½º¡eÙJÑÇ„yý–šoDUPË “=ÐAŽëÎ,Ì›C§›å-:°ÊÅòVÝ,¯"ºsÄmA¿ÊÚƒz¦¨pPqvù^«KÈh1ŸÄõaH9ù¬&a°*é¾’ŽžfK¨­¢t3yl»—ª›ï«Ù ¿°º§Ù„ðòݘʱLÇÒkÈ‹­a‚^>Øœ˜VˆzM®stZ¯Ÿ²œŸ„W²1¦B3Èæ;¿:è°FßâùzûH>œ'Pæi¬:à#Ù¥|$GxYÒ’C±/ª]&Ý`ÎÃ_Dw¢:×¥ŒD*?$’?(åúÅ IÔONC`%–Ôñô¨øAV ŒäöÏ>³” špy²1q‰q}èIgÅÙ[ÉJ°µ’­¯V®z.з¡U|‚þ°n‹‰‰ÿ |ß’+)v¥±åKæ7©ûì$|%(5ð±ÚЃ÷gìL‚Ø!oŒ ^ ‡ +« â¤8Ž“Ù¡kÐôfbe¢±2ùXiѦCÏÄÁnAŽÁG 2þ.¥ÃEÍT F+ôsºA40Úv#þE 0ìÞŸêúTw}jt=Ðoî§™,asJbšXp· \™K–Òd¢»Á(½ öCü|ô‡ñTG®tG®ÞÝa«1—!Ë*¢í(Š•X.kư°û„ìøù¸µïìϵîÏõ9ý1»c‡e±PÁDåM^J5‹¼S”J"{ ¥Zo´m¹ L4Q˜÷ }ß­ ‘eÔ×|¿=‰‰Ÿ8v´õ͆ˆ$J­§B+žƒÖõ$"P ì±ä¸ï7»‡7\—p3à‚?ã÷Ä`[Ò{Š ²ì‘åJ%k‹‚ L”ÍX<Œñ¼žŠÄG‘Œë(s“-ɼ¶Ã¸IN23O·å ¡ˆ¡³•¬þ "žÛ+‘óv¤öþ€²Ì†rƒ_Q†4V!©°½L¸#U% cOÂ3Ô[6¤Ó¤Ø.k‚°Ñc›;Ùá{‚9ÆÛ/Êého¿(möìû$ÃÿS¿ë!” ÚõÐ&¬ Š6)mNìúÍ‘ö§B·iZJÅU¤ë¨y NðQDÕP4ð2ã×ý¯1ð¨mŒ,Ÿ‹6Ž!àöØ ©£Š½B ÿm/+ܼ¬pCð²BÔËŠ¶w¶‹þrç€Å Ë\Ç1Pé%¤b Êõ+ˆŒ<ÊÀ©¤ñмË6޾"Ê =ÇzeG_ål„ûc¯ÀÇÊY/ðŠ—U·}) ¡*mº@‚h[ÏVdxR!Hû²­F ÆcA)Ss[s¹ëô­ïõyI &z¤¥/‘iÇ@ö[‘êì‹S+¼ :ë ‰+?ש¾ño¾ øˆ}Ù—ôÛûðd³g¨=œìÿ+N}¸q¢(p,S‘Lz^ Žm»OþNîÐIAQb3¢.Iq¤°(ÑbNnzâ6©.Øy%Ïvcfà …,Â×Ê+åS ÙA9aõÑphèåœ×Äè½Î´¤äÑöóa-Q±àľ£µcßâ×8·jã†Á½-s­¦oFfpÞ²­0ÜnÂ)X)¶}ÊÄ)Í0~Bõ±Àr{_Nû^2`]tâu³«ê2˜–tƒWþÄR’©yœÃk\u’+/J:èwf–À4A·É÷By‡ó4Ïx ÜÐß2(67y7?”x;]Š'¡³8:TÄÊì‰)FÐðÈòÛN¹ÆM`ó[p ]NÓ®Câš^ÜÛ'q,qýFBJý*CÅþö0 ¸f“EÌGFƒ 0"ºq±bnÚÎÀŒQ(FÓÆÔ36Á(†>U>¼ûƇµ¬.x]Ó²ÐÆµDkx’¯'òÁféRé¥ê·EY¨m=+ñÖ@aª~x-ñ¶qçm±(ñ¾qkþ¶ zfÅy½¦šæ½—ERÒãÆù+ñ‘qoAåð‰Y9Á›ðŽÕFÝ«èÞ‹y ÍEp¯2ïÕT ÙtÛ7uSã´€ç`)ðD-0ôL܇oŠt€KÃchu©FoK|d¼ôEpê-µ*R}¦Iî–·{Ú§û¹L³‡hŽü4KnÕ8!5Ô*›—ÁùÇ…87íîðð„Š/“¿1ÔËÐ!dÄ'ŸP¥E­¾VٓàOóŸ€²:W϶&6OðKlR7Ûe‰OZ ¿ìÚ%bÝu±„ ¯‡&"¨lÎÂåÈBccâ±ù0"Ù%¨âtÆhäÛÎf‡Ý')a=™´9*›y öF»LÌ.–’梚•öÿåqH- Lx0̶eýà˜3~×(*âºëî˜dx‘­6™Á·™›ÝŒØî†d7#¯c3äâ¬eÌÚ‘I• 4™p# |fÎh%ȈCÀÿš—žÂh€V4ätÂt‡ N}}xU_%à»×0AUâEFž§~,B_ÔãJ}CñC~¯Õ7\6ýú{iiÄù£¿·Kó>¼X©Å2RévP»’¡f-c ©-Èã0®ÒŽ€æAt!n–flDÈÐJ˜¡u0#«`ÆÖÀŒ­€Zÿ2´ú­è8& «º³­Ò *÷†ßaß¼‚›ÆŠ ÝJ‚Á¾{w &ûö×TdJ·oßÂm€ÙºYŒ±a{góIÌeö“ÃWÃó7¸‘á#±;q‚Äž’F£¡lÆïœ™ õjŠú¦Þáþè¤T­àì<5'…Çøú&e­+ÓäÌÞÙü-{Ðø þêuö²Èp"epë%«2ªZgX y2XÂOç\j?—ÆUC’Ø¡âa]ŸGÖEßšª‘ñf îw¿KJ—6ØØ„!eDC¼ÃèL‰“"ê ­4z¯æ¸Íÿ&°L_J×9ã[ZMžï¥áºi¼-(>/‡”å;âÔk 4ïU~¡§Hzø UVàÆô¿¢ÿH‰=&åP}¤ÐÓ5nÔ³=T‚‚@ =úÝ.©é="¼Iüvˆ¦ x$Äž Δ©“š¨{0•°M¿2]O‹¬)`¾†½P” û1eè ‡À=gpû 8ÉB[6az¨È{:1< å…ÖsºÅ™¶¢ã vÑË5†¥¿Ü@ß6ø»'®t|ŒñÿÃüÆLbÒ³ >k)ïb6qV²À-:›éí›*XæNËt` ÆbSSRWäQÉSS÷KCÂjLC2µ*4°“+›¾øaZ-5¢/KÈÌ£Öéb m¡'T@ÅDR¿N|•©ÖŠ€yB?)u5;åå~Ú‘(Yƒ0Zjâ”·aÄY§nàÆÁ¼qUãÀƒ{¸}oÜD"Û5Ü®­ÛòöjèF¸‚Ù†0£c<¡þÀƒ|,H„SÄΰ·ž*öµ5Àtœ[EjéoðÖ$µUnD^ÓLíX¢ ÔîãçÐv: VNv8] ŠP“BŽæK:IEÓM¬ÄT•Ðk¿²ÂŽ‘l0 NöI6œ`RØ€TØ*üæ ß1 W¶_÷´Ýµõc¹kÑ>gl³OÕº·ÂÛ¸Wd°ÿÃ\,ú½áØt>î ƒÍ@ØrÒ>Ú)ùèj>NSÝ Ê€-YÚ1Ùþ‚¾‰·iŸH…ÒŒóTÏÚ>¶³ ¹R¯{(_U0¦X¿§&)ŸeÅ¡«ÏÆPyÁ·YÎŒ;¯xãÕ¸0 % ,æ0oǘgž†‡Ò¬‰+‘Ù:ïqIàí,"D#~#‰¤8d\¼’’œHFò„yѾ#fð&9ä¤Éãváya)v Jg6Ô]ÇnÅï±èL´³LÌv7 &”©ƒHY– °þ\e©0Ñëj’­Ú¨ÝÄjÛý±†Še å*‘I"‰{%ã^Žq½D B‹ñrí4Nª(åާ'­f¸M£<:]]ÍŽŽÏG½îiø»óÖAŽ|KúÆœD3&ýL•óq‹zš·@«µ]úXŸ¢Ä¸Çè· þbÂÒ"·—$fušo:]ÔÜJÁ¡‹‘×1þ³·ýY¿ `Ôn÷#&&Ñ™“¢Ì‘$ ç g"Ü¢[ǾÈsOœÃ+pL)N™4…$gœlpÖPl‹:'1{&e]Ø- ü#÷N=¼HÜz*=ã©.0§u†ÅõÖ}5^À•6&žØa_'H°Žè‰ Äcb“'‰Ñ‘kÑ?oø-û>Ï sî~AiM]odYsÄ6³v½Þ—¤uŽMÌ7’ É̆ … ½A—€äòA´W‚‚–@YÃÔ³$êY2õD 9F7º+áçÏ”íz>ÖÈÆ–$ëLžÓ"ar©’j±–—þ‡1êC å>×"a­SXÎ8GTÛ«áMOâÑ6ý¬%÷:ž¼ýè¨ÄNXä4°„uqŠþr]ˆH6±ºo«Y¹t·õL¦ù¬7ði¨ijT¤7O¬âmBHîËö¬Eo—R‘îèØa?!ôã‘DÊZ­Ît’¶,›kÇ•îÍ¡†Ð¤€iò`[Å {ÞJMB j†”’¬—{¶P<í ƒ!™*„Î2ÔJˆ2…ƒá³d›cûÑEÌœäKèù’°Ìòùµ.íÌ;~~%]›L]&Mnff$y&O$ÜÑ9û“Ô,BóöÝÄ`»/7ÅX¹‘ÌÊ•RFJ²TjŠïN‡ï¥B¿¤ËwӠߌ4j}3~úó©/F{‚–Îáu@,Ïu÷ˆŠÇd³ma»ßÍæV¤ñ#wZ±]T;6 £zù¦Èü~]£.l51?Ó´?5êäcÖU\Mz[}ÒÛ_‘Þbä†Ü!99äLo‹íS-kÂkZÊ&”¬ˆ)]]E)#íš0(–fÈì“BþPˆ1œ¹=€g1)ZÞ0”™ ¯pZ»Ku­¤×òu°0àq zÆ-Œ¥^àôƤ³wZd2eU2ÙJ-¥eÈ©ßnM—ÝçM¹ïáÀ>¬~…MPÞ¥|uê:‚7m. ˆ½ÖðqŽŸ?0_ž†Š6IâàßCfßÿë{‹ÅBë0 Üœ52ÜÎjÝ¡LC#?Ìgcc$,µÞD«àºãcÐBaént°ñU ¥2“ ÔEô^oE ßj…É6B¥P‚E‡P0¤„±õ™k9>1ób×5îEõסø:´IÔ¼Þ«ܵ¤\…{3¥î^+Ä’Ž5=1P=.8Œûm—%®'+¿#üþ÷ûÐÎ¥pœ€s¿4JÖÖÈy% ‰ïħ ¼V][BC˜„ŸðØQCéäÔ0e Z¯F ½î=æ5Æyg¸3Î|åÑÝ2³Z{B”ÜÔ%4¤”ÇÝæ"%Œ­m„ šc(¢ K)¥¡u zªìÐj#½änø/cÔúC¾ïßUw˜ö-'ËEE…Þ׊Ó_ÞÚí¦© "± 1G±{ãyäÂÛ4èÉÒ_O[Åk]# _†â ¡ÆV 9„_ Z|=ƒ/Û{åêb,ŽÕ÷l£¯ ¨gòý«YxOxƒœ¡à‰:¬mîËfÁu…@Ô©Oȵ(5éÏ´yR¹Â|ÊÒÚ×qlá… ï¯‚/\͜׼@ñ!žÝð+1°I* s,*$K£}4SÕ›1ܰ³” ñÀ0¹’ÄÑ ©f¨éÂ}‹U‡ J„`²!2‡Où²ƒAÁ¯cÏölI¥¢exðhƒtb¶\tC´´Ýa“x¢„ñc´fÇðTVk“0"ïDÈl ÆSx€$ íG+5w𡪨yX .«ž…Oðuªˆ 'Æ€˜!ZÙb«œÀÚå?:¸|ϾFQÂÉ} my‰z«Ì!2VɨSxÇS Qѳ¡ÇQ¶øÃÖULj€ÄMÇqÂ$'SÍŽ0H:±°ÉØG u]F]¬_ÀhžûŠK*m‚¨ÞLÞñÜ’­cãèåíÍmš¼f°_€ozSí{_¨,'S'÷f ûX~Éæùtt“}¡÷Š_©ùî¡órM‰pÎ?},{—’û¤K¶ð¹OšzÏ·k¸±>Õ„x¥íÄ¿î-ß«tõ–&ÒyD5g*8¾~ãˆzÃ+{LßÓnxÄÕ–K+›…8P¹Ä¾`;ј”X*Ö±ã©Qr2*™¹AeÐ %ý O.ïšõJzühBß½=ä×þQ·vá[î7cz·Û¾íʳ]:®ûumGö“.é*0"€$†¡ð(KýļÈÏr ’Ù·9à'-ÙSèfó,}ûbY.pÛ´T[°Å²!ÇñË…Üý‘°JMÓÁž , ŸêiM+nÑÔ5-h¤Ì% éþÍ­\^02 þäg.†˜X‚ÓÏêù’“žégy79Š2Ód?X,ÏóK´t,6_ô&Å…{%ó¶ç¶s{ý LÜ-“_Z#§O>ú|3‘wã*8(„&þ3ÜÛK‹¶l͉ü %<1 µ ½‹îàMÅEI(ò•s±S gPP½i†Š9âêÞ%›z¿ØÎϧ¤ é¨="R~h®n#ê±"¨ÿ˜N+c\ïG¯Q‡–û›\ cn(Á8n3œædS¾HÈÕÒÀ%Ñ ¿—Kùi:ÂŒ¿oÖ˜-„by`ÚrËoY?9â'Dµðªqï—BÙöû¾†.¢µäFÈ•¿tñ¸+”Q7³¢‚r° ¼$_"c“PÔŠXp—³IP¬Ü„qm¶²<ÕŠhþ´êc†–þËQ¯¼Sp‰Â6)o#ˆ†þ~haׯf’âñ :ÕàÉ¢#O\da^/þ÷±˜ëñÛ§–`uykñwšá„uäQ&#zzÔiP®Ä4׆ü£‹ä;&[Œ„Î{ñüíÞÆ÷{E‡°gHïÔ"Ì®âÜrÃâ9w¡9wáÃÍG:ðÙ¥pgq¯Ž H»µ)⸣ôÍCtöÁ Ptt¢`‘ëy²Š#!nꆄDQ' *ÚP…M>g‰qPýc§OšøÙ£Ž%"̽ÃÕJ[ilµÀùÂ)Q|ÔÒA Ü2+lËF,êIï™%y‹h{K=ë[˜2öÂè[îÉ<èñçPÞ'›ØQÜ¿œsh7bøH]v½"àu¾L±U>Tׯ½¦É^³+ü5ðÑ̾K´ Òóéwy‰ìÛ¦=`˜s™ˆ—à±ruQÄ RáQ‘¡¡4Ô¡7F˜ŸÑЊºÕÜÃHÞ¬1äœgMƒêEÜ^j­ÔE£oë» ú¨»YFus=~îÇpȬ‡í$ j^<­+N¾àöSBU*Od¹ 1 Z‰f ,#slšŠË9d±*t¦²#¼¶[;§@õ\5kÒÜòøožF_²¦1–·P8­Äë¥m·râ,W¢‹%½×!¢ f—r"Z/ÉMÇ®©‰Šñ©Ñ…{ù é†Ká‘øIŸå™!3§ŽŒ·©:TåÇHOü1ùñ‡Ïëóú¼>¯Ïëóú¼>¯Ïëóú¼>¯Ïëóú¼>¯Ïëó2¯ÿÿ!¨Ãodepkg/src/Makeconf.in0000644000176000010400000000307710731466235016066 0ustar marcoAdministrators ## Makeconf is automatically generated from Makeconf.base and Makeconf.add ## in the various subdirectories. To regenerate, use ./autogen.sh to ## create a new ./Makeconf.in, then use ./configure to generate a new ## Makeconf. OCTAVE_FORGE = 1 SHELL = @SHELL@ canonical_host_type = @canonical_host_type@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ mandir = @mandir@ libdir = @libdir@ datadir = @datadir@ infodir = @infodir@ includedir = @includedir@ datarootdir = @datarootdir@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_DATA = @INSTALL_DATA@ INSTALLOCT=octinst.sh DESTDIR = RANLIB = @RANLIB@ STRIP = @STRIP@ LN_S = @LN_S@ MKOCTLINK = @MKOCTLINK@ OCTLINK= @OCTLINK@ AWK = @AWK@ # Most octave programs will be compiled with $(MKOCTFILE). Those which # cannot use mkoctfile directly can request the flags that mkoctfile # would use as follows: # FLAG = $(shell $(MKOCTFILE) -p FLAG) # The following flags are for compiling programs that are independent # of Octave. How confusing. CC = @CC@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ CPICFLAG = @CPICFLAG@ CXX = @CXX@ CXXFLAGS = @CXXFLAGS@ CXXPICFLAG = @CXXPICFLAG@ F77 = @F77@ FFLAGS = @FFLAGS@ FPICFLAG = @FPICFLAG@ OCTAVE = @OCTAVE@ OCTAVE_VERSION = @OCTAVE_VERSION@ MKOCTFILE = @MKOCTFILE@ -DHAVE_OCTAVE_$(ver) -v SHLEXT = @SHLEXT@ ver = @ver@ MPATH = @mpath@ OPATH = @opath@ XPATH = @xpath@ ALTMPATH = @altmpath@ ALTOPATH = @altopath@ %.o: %.c ; $(MKOCTFILE) -c $< %.o: %.f ; $(MKOCTFILE) -c $< %.o: %.cc ; $(MKOCTFILE) -c $< %.oct: %.cc ; $(MKOCTFILE) $< odepkg/src/Makefile0000644000176000010400000000475712007561775015464 0ustar marcoAdministrators# Filename: Makefile # Description: Makefile script for the src directory of the OdePkg sinclude Makeconf # This is needed for packaging OdePkg correctly DEVELOPERDEFS = -Wall -W -Wshadow TGZUNPACK = tar -xzf # "tar -xzvf" to print some output PATCHPROG = patch -p0 # Needed to patch the Fortran codes # MKOCTFILE = $(MKOCTFILE) has already been defined in Makeconf # MKMEXFILE = $(MKOCTFILE) --mex MKOCTFILE ?= mkoctfile FFLAGS := $(shell $(MKOCTFILE) -p FFLAGS) ifeq (gfortran,$(findstring gfortran,$(F77))) FFLAGS := "-fno-automatic $(FFLAGS)" endif ifeq (g95,$(findstring g95,$(F77))) FFLAGS := "-fstatic $(FFLAGS)" endif MKF77FILE = FFLAGS=$(FFLAGS) $(MKOCTFILE) ifndef LAPACK_LIBS LAPACK_LIBS := $(shell $(MKOCTFILE) -p BLAS_LIBS) $(shell $(MKOCTFILE) -p LAPACK_LIBS) endif ifndef FLIBS FLIBS := $(shell $(MKOCTFILE) -p FLIBS) endif LFLAGS := $(shell $(MKOCTFILE) -p LFLAGS) $(LAPACK_LIBS) $(FLIBS) EXTERNALDIRS = hairer cash daskr EXTERNALPACKS = $(patsubst %, %.tgz, $(EXTERNALDIRS)) EXTERNALDIFFS = $(patsubst %, %.diff, $(EXTERNALDIRS)) SOLVERSOURCES = odepkg_octsolver_mebdfdae.cc odepkg_octsolver_mebdfi.cc \ odepkg_octsolver_ddaskr.cc \ odepkg_octsolver_radau.cc odepkg_octsolver_radau5.cc \ odepkg_octsolver_rodas.cc odepkg_octsolver_seulex.cc SOLVERDEPENDS = odepkg_auxiliary_functions.cc SOLVEREXTERNS = cash/mebdfdae.f cash/mebdfi.f \ daskr/ddaskr.f daskr/dlinpk.f \ hairer/decsol.f hairer/dc_decsol.f \ hairer/radau.f hairer/radau5.f hairer/rodas.f hairer/seulex.f SOLVEROBJECTS = $(patsubst %.cc, %.o, $(SOLVERSOURCES)) \ $(patsubst %.cc, %.o, $(SOLVERDEPENDS)) \ $(patsubst %.f, %.o, $(SOLVEREXTERNS)) SOLVEROCTFILE = dldsolver.oct %.o : %.f ; $(MKF77FILE) -c $< -o $@ %.o : %.cc ; $(MKOCTFILE) -c $< -o $@ all : $(EXTERNALDIRS) $(SOLVEROCTFILE) $(SOLVEROCTFILE) : $(EXTERNALDIRS) $(SOLVEROBJECTS) LFLAGS="$(LFLAGS)" $(MKOCTFILE) $(SOLVEROBJECTS) -o $(SOLVEROCTFILE) \ $(LAPACK_LIBS) $(FLIBS) install : @$(INSTALL) -d $(DESTDIR)$(MPATH)/odepkg $(EXTERNALDIRS) : @for i in $(EXTERNALPACKS); do \ echo "Unpacking external packages: $$i"; \ $(TGZUNPACK) $$i; \ done @for j in $(EXTERNALDIFFS); do \ echo "Applying patches from file: $$j"; \ $(PATCHPROG) < $$j; \ done clean : @echo "Cleaning..."; \ $(RM) -rf $(EXTERNALDIRS) $(SOLVEROBJECTS) $(SOLVEROCTFILE) distclean : clean @echo "Dist Cleaning..."; \ $(RM) -rf *~ config.status config.log autom4te.cache Makeconf realclean : distclean @echo "Really Cleaning..."; \ $(RM) -rf configure dist : all odepkg/src/mexfiles.tgz0000644000176000010400000015652710745667503016374 0ustar marcoAdministrators‹Ôn—Gì=ùsÚHÖù5ü½žõl%@@ìaË2ˆ˜„ðÄ©LÊ%‹Æ¨+ _Êû·ïuë|_É,*Û’úxýî£iÛz14ÇÔÝzó|—WY–ù½”¼û×I,åR©œ/‹oD©P,äßùq ¯™ëé!oú#{¢»×»­? $¸ÿ"×$ÿH7êäæpøÔk ?JÅâ5òa—ÊüKÅBä/Ãõ†¼ÿÇåŸÍf ýÖÀ8Põǹ!!yQVÌgÅ2ÑR€–´0ÊJ’Ä(+Iùk(«×ÓZ/#ü ~èô;$- y¡ Y( eA–ý/ h ‚T$9#æÇÎ^ŠÔØd‰0 5µC5•Š©’= ¨ ìJªƒ$n‹å›T醹âûíÂrUª”ß#¿ñ¶œÝ_Ò` ü®ÓL$[ÐÙ©muZua_h¶›ÀæÉâ…cû*9h)5•t¤ÙÌö÷YsGSµ> ‹¼PH ÎßfU$!F"“UIЦfƒ¤9Z39õ\³™) ØSÇ”}¶$™RáëFÛ¼any»ð~)C • 2oq†¶”^¿šk(­žš Øo)í=P©Å0 ¨ø¢u4þ0]iJ×´´& _„OS¦û¡`öÛÊQUÙë¥ñ!ÚBèn½*Ã;"ZÊ3É— I“k½#ûr½H㲋‰·.W“ÂZ¿U¢Ø'_c2 ¥Š\˜—R‘H…íBu‹„—Ìe.æ·åüR CˆEÆáíç”pÅ—pEæ¶]ºA•'”på™$ìè}x¶9 ¿ß.Þ_ù\‹ž'æVˆTÙ+Ëæ"ãʲÛä·ˆqM­®å«Üó9M͉‰Žë(ø>7cül+½üèw›G¤Ñé’fû Õ¬5û òžŒ†+•q ÆÔú® ­µ%¡B«Ž?cº±yË,Ô¦å3}"þTºMe¯ªõÚM-×êçàA9ŠÂimU´~/j ¦«Gªоáy2œ—ó¥iOëK0/@ Æú.¥yN«Ž?ãêÃAwÕ;©kÀ¡G)œ n¡Ùˆ±PªæúÝC5kÜW{Aã‚OXˆÍO(ˆ·ú„ù¹’D$i;ÿ¾–ú„Ò{–˜âM™`jdccãºoì¿Ðì7•V³§ô!•êÝ6%©°¾/Mjl²‘©l²É×ÙÀǬ—ÔA‚/Dcòô£À^«SûÄÜ.I˜³¶=ç«ù ›³È]£(ÿO¸Æ»z¿Þ¥j½÷G·Ÿ.1Ïè¯TM¡! ý™-‰åÌÈ‹L™*Eyeä7¹Kgã°¦IyŠš|é\4r˜[Z6—¹\DëÞdw)&™€”z'Eæ(ûµÔùy\Ùïôç²?ˆàuµšþÔÞÌg6´n=l‡Š»ÚF=ˆZ¡å[˜‹y_`ÃûbÂ8m"7Jã© å±æ²Äf®7œ%ÖÃöP¤r‘í¡Håò5‰O= *vŒÐì>Aú¯%3%ÈþYŸý/IýIh^‰ ot÷ÚÄ_.Þä—ÍEû¯lçKÛÒrû—å‚ å±¶ƒ»ü,QÑ ã7ZÍ’P Îd>:‡¯…j!zÅ4ºˆ¯Ïã¦ÈÃü¹kÜ%=µ ¨£ÒUÚj_íöP'±Þö;õdÖÂàw;…§±[Pò€ð;/(s•"Þ ‚•"óŒÏEÁŸÿ/æÔ øj0§VÄ{A¨ÁœÌ©Éø\j%IàA£ÄÌ­T*ÿºÁüVD6y&”Ó:ýœrØ×Ú½ ŠE‹‘Áª7ŽÐØE¿÷µ·íŸì ?ÿiëß)>=Ãè®ÿüG”ÁÃÏþ#‰ùÕç?/qýFjöôÒ1OGI×2b*áÄ’¾CMc4&¿{üawæRÇ͹öÌ1èÐvNi΢޿S¿‘΀|?%Yr ßõSJ —¸öøÌ´N‰í LKw. ~¸Hjy¦>&ô?3Ý3mË%ç¦7"¶áég4õëL—LûÔÑ'‡¥lèëÝ!—öŒºE:0]Ï1Of%¦Gtk°«NlXæÀ@ÓÌP‡x#J<êL\bÙËí| uƒÙÉØ4HË4¨åRTO±ÅÑ9A08¡ô| Hø ÷BwXâ øï$,áÀx€‘Ö=DÛ!ö§e×K2Ö½hfn)åbZ ðÈž5#ô›ã19¡ä2œ€cÉç&„”Ã>¸å/ä³WëÙa\¶¡—žQÉœLÇ&šÝò.uÐV»µ}˜¡ì5[ÍþÀŸ4š}M§ŒÞXÁ®þ°¥tÉÁa÷ ƒûĤG)ßM¼2éÔÓͱËiþât³ñrž3 b5¨yxéÄÕ¼]fCÛ gL¼ wˆ9$–í äÜ1AI<{Qš0;’§@š–‘ˆ,Á Ýú>¦÷@ù)€h˜CßÛ¶#=Ûõpx[!b^’ĬT%rØSR)õÂ;Äz‚<©ú‰\ØÜh¶Ô^Øÿà4…zëmõˆàL{@§ßOÁE£%QçØ/¡!•ÒAòÛäŸéؤL*õÏt|ù ÙN½|˜™ëˆde°ä˜·ÆÌ“¬K²=2ò¼éöÖÖùùynf™`øÆhë¿> Èí- ,ÙûŽ>nÊÚóŸ@="ÿx#‘5=bøc‘7Ýß×àù­èoìͼ7}ˆ±*"‘·>`|["´>bt| 1´‡@ŒIˆAŒ\*i> àV‘z;Õ=cD²S‘üNbgdЮ daÆù+X䢵úZoø=Ð>Ó ž¬ã. QíïÒ7[A2½7€é·€ ìãV€\ñ[úòWêíÛ·sÒ^&«;.|~†ô„+3CºÉÜàžnaßàn%90Ì»®œ2Æ2,ˆ΄dá|h 9¾N,oË×7þûÚéìêºçÖ 5y'7yŽ5n®ÿ$Q.Ï×ÅRQZÕ/q­/)KYÜh¼w¸+2]RÞTÿa~ßá5àúoëIªÀõ'*ן¢\¿[!¸œüû–‚ë®×[ ®ß³ä„?¾\\A¸þÔ!ÌndA÷.Lkhã36íèлœÒ¡EÈÆÌ2p9€9¦WäÇ×Ý3ÝùqõT¯óÌ$ÍZvw‡3ëJ ìÅÛ^ðlZ&>óy \Wß‚—©îHÁ(xÎãóÀö\€žIâqA~ÔìÉ,(Ä,÷õ‘á_†À/hØ>™ôêÛ àç0ËÐÐqó Z± TÖ¥j,TžÙ,+KnÝ KÇÆvꪛA«‹µ%¦éãSzâè üËÔ[†/4è`útŠ®Ñ&»ØúãºlþŠû Î%û,_|碫%ŸuËb/ ÛñÀ@8áŽÎÏñ¯Ûn¹9†¨À³¡ÇèyÐV-ÌÝ›9ÑÓÙˆDû´ÈÇ, ÏØDñÌ Eg¨I§3p%ç¦5°ÏÉù) ¢›ÇÅ€üä”èÌñ M‹»S=B ©r§Ô0‡&óýl~Ø;‚n€Ó-ä..`Ø‚šÎ¼ùHë8¿6x* ®Þðl‡#‘pytBzpx\Gï4G¢>œéã ¤6u}`¨ãLKyè®_¢Â‚ŠzÎÌð}èü/9ðï”N9h>ääPÝ …7S²ë? òŸ¯o±¤%ˆØ,€&È(Á‰¾#Æbè+̘ê®om bÑÅÅtG´-º\ýÆ„†>’qqœg¦>ÄØ~*úª³m¤sÞƒ Ž.︈ñ•Á€‰+Љ¡íøBGÉ#Û¤}õåFzÑ;òñõƒLA7F¾~|à#%„hà > Á1Xh°–P=b¢Çn(V)ähƒ`}2%+‰q†ùüÄès c!*°uÃÁ9@Áº0Öı<ÝÈ”Ð(|s a„Ɔ¹”S+TÜùFß{€Ê¡øiçÅœÓ@k½«Ê², ´î¤¼‹}Åò|¶†ÜôH ,¿¢¼Öug ƒ @JÜÏÅ¿Ÿtbóä÷>±^ö¦)>ü]—R}ìÚ~à¼J¥B!}\Afã{ù˜“ð6Ó¢ACÒºPw½[wßeÈ?ª¤À?·¦Žz˜~צÙp‘µå×PE ÏæpPSÞev CzŒÀ"ä~HÛºú¶ì3/BüÇöƒ°€ügjýÈ:¸Á *xú]—Žûöø@$š•òN9qÃ÷<‚ñ_Ï.rvcÒ®D˜Òóè ™uÆú)$j"ÉçäoìA„[.—CPp)ª $/1'²Ÿ[{Y‘æ«¥·)ødí“K\äw§°+Ï»œ Û#è8lÌM©uêXàlÈløéÎlç]¸ÚzìèÉ#.ªÏbA<Å éÜ‚<جcê'¨åÒƒì9+ñ# ‡Ã£«kž‚)“Yhq üXûeºz‘ϰȤ5ŒóP§žpÐ(лp³LÜoX–çØc|¶Ë o¡²rñžë.waa6ù-%ˆ÷.Äzpa¨P'¸ß@CCöáøyÈ׺5F2œ9,©€Üb—¬ÍiÇ[…œ0™Sø±ú–”=ÇJ¼– ‘?9l³ƒUÐ>´¶ýmÒ Mµ¼ÿµ·ûòà5öÿD¹\*.ìÿÄÕþßK\«ý¿Õþßjÿïgßÿ“?Áþß«!ñ€ý¿gÄõ×Ûÿ‹ –~·ìs¬ŠÀâ pP"ÒlöÓÌótYÒÈø98¥´,3eîžüÐl’™DVÇÒ‡ë¶ùÙK("ƒhwå@á€Æ}ŽUjà=Å\1'²MO¢Ácªƒsày\sbŽMÝ ¶|ÌÍ*rD7eSP.ŒñÎ`*ITä®:ç+½{•y¨zñ2|Š…Á/ý®Ç—ãcÐ¥Ó)87¶©ÆSÖ9– Ô|0Žð.‚wèÓ@/øÁH IãSo¬8¹¨Rrò™OXsr€/Wt2o±*:ÿ®E§õßSÿwþC^YYYYYù%€ÈÏsD¾÷mÇñ™O}ä%·ãVg@þÖÛq«3 ?Ïøþ_åµÎÈ¥Åý¿âjÿï%®Õþßjÿoµÿ÷³ïÿU~†ó¯†Äöÿž×ÿ­óA <R‘ s'@*/t¤\¹át>Ï ÊN€T^äH¹rÏ ªž™O{.–œO]jVV'?þÎ¥feuòã–R3^ÿÙ¯Sÿ•¤ü|ýW.”VõßK\«úoUÿ­ê¿Ÿ½þ³/~‚úïÕx@ý÷Œ¸¾Þù‡ÿ‡—oøgÿæŠ7ûâùŠ·My Á‹06ú²Àåc%b“/(ð¢,ÿT¿í$k¼§-îP³n+î`̃‹»+4”ÆCê3œ÷„Õ‚{þÚŒÙðª6û»Öf ÞUmöêÆë¿åköñkÜ\ÿ•Kyiî÷¿ób¾\XÕ/qmm¤ê¿û—~§úóÿ©'©úž¤ä{|½w—boàûÖy,òWáÝ«¼K=¾²{LY÷¤5ÝÆV*µµAú6x3cÇâ öL±à'õð‰á9 '³SHo]ìÂMñÿ+3ÿ‡³Ÿñ<[ö3|¹#ƒz¶~| ÙÿÁ§uuïðÃñ1ù‹O½ÖOßùo‚#ÎZ êëãÈ!BgK0¸mi¾\OŽÍ2 b®5¾Ô0ž™ºŒ,³ÙÿÌLˆÀÙ,=µX‹g–­ñÔò¯5–KB=ð×O.ý–¢ E «Ã2œ†aa/Ë/Óò„°§GÙ¼¯Hß°¹ËŽc[!³@úZõ¸ñ£‹ÅÔõLG§4µÇ1|¾Š|\ÓWHZ¥|f)Øo¦eŒgJ~‡d r¾Üèß8ôN£ÏG‡kåòqãP«ñ“Ï&c*õŒ(”‡°µÅÍw“s‡årvhX|þ"X‘õ¿à€Ûa'Ó0\o`Ú‹0\&‡a¤HÁ­Á»Ë¨Ž>˜Ô„2wTã»=ñOþsú9ÆÏîÙ¯[ÙôðCëmÌ¢¢Ãçà$˜Ü'3õO¡D‹œÙæ ²“47RÔ;pÏýPflh·Ñ¨Á£¬xã(zü‚ÿb-lWµzÔ…ÿ×9zSØÚdn/j…xö¹ÓýäwµbÏÍx»ÿ®ˆÿ×ÌÆS„¿ýÙUûP|¤ûã#â±4Tÿ¿Ä7›KI†AB˜ýÇsI­ŽḴu>b(°/ÆÒ¥|  ïµÚ±ÒïwµÃžZŸ£q¾7¤9C~ø¸‘3~V‰¸6X³IÐ`Œ Ç?›¸§_KEtÚkk;_& û ²qæM¦Ð®¶Z;±Ž³ñÈ]ÞáÄ:RÌ}€h‹žà&ÐÛ#„òúØ <-‡æÅ௠2F%ëâæ4D‚µ`2!nlƒÅ§hr ilÎP €§ýa…/CƒEØï4z³il{HËF¿hƒCœD ÃÌg@:¢<´$íšÿGÖ¨7Ã1unš”ΓMFL†l |¿1rkìêL%zà–IG!­X¿ðSü×Â_ï:51óe&æ_A9¸ WÜ Ö“×kët.`=PdI€Î®ªü{ïþÖÆ‘ìçgþŠYΰ ’ÀöÆ$9‘¹ÄÚ$’ødýÍ#¤f-4:3âv²þß¿uéûôŒFB€71gß7²Ô—êîêªêêêú…Bݬ¬ðÖ^åu9Æn „©ú ~­eŒ–ù{•Ç€.?ZÛ‚ê*Žhm|\*l¨¾±ñi ˆƒV§3ÏGSÉÿxñBbRUúªþAòÌ:ˆO*TZÍàÎr‹ÐeÆCñB…­°›8ù˜ŽA¿ù™NòÃâ[(×XþÃF÷ ñ6X©Dƪí/ 2Ò[‘KÒ;üzˆ™z•·y L„ÜÊÐ!¶ˆÅþ¹üuúÏeòÁY#,ç6Å½$9LÏ»·n~ø$æ£COÌ.B¡Dù`ZH?ó"÷RpÆ3’á‰}ƒ4 ‰·Wsyå ^¨(ÈI(b}pCZ¼« 'Ù‰]øSVd§hîƒfR"»mÈlD×Í‘àB¾J u…OSd%¸-ß= ÀPkü±Ým· ìi™ÉÓ«>0÷Yo˜†ÛšøapJ[dƒ¤ÿÕÝ™tžžÀŒ„gR-Ø?8 Dë£åµëA|jèãûÓ¡OOä)–ëIxéÿ>òŸLr¾¿:jh'œãç²ržïXì¡w 왡 VЂWçŸU±¿ïê²’ïiS‡—, ™Ð©ÒYí%ýöKì&qa¾^=‹’tBÞ`¦%ð#ÆÚj€œ çqì(>ž!š 1tzf¦³ôçJ´ãa<Éi»¼m¦{—ãÉ.Á³g¢ö!°íù,©›"¢éø‹¢]þ,àBê ÞÒòCRHnÆ»ŠÅ@¬lóÉ™” þJJåì¨ÉþîDö³%dWØ1øŠäSqç«°å4(å$f%Ð[”$ ˜²9nàÎàÈѵ_ƒu.ŠQ èEP—rœ§`’ψ؋QOdÆëG2ÈÆp*»ø}áÔ ÇBÉ,}Ðÿþ‰k/D!6X naåðp!Û塳À¨m³èø×âÏZ-Ëþ ¿^'{£À.†¥W¨S’®B°²õ­ºw6*ö€Õ@6äí=ü†°œ FÏå襠`álk¾Q¼.îÖ`UP«_+ji¤&^^Öë÷IüWé0hYüÈ?Io5N[w~Qã´¨¶PšýÌq6áx}žôÄó\yÃ4‰Çc<àÓñÔ(`^’%0ù^ñ†é)6\בPB[tˆ—½ü·œµOÒæpÅľ./xäÀ 3tßWëu§WçgÑm…|;ú%wîëy硲 ZÜGÏ'*zZé)?ð„nÙñ”1 ohu´}$%k½²&v¡‘r¿”…mð&rÿ˜óm¯Í¦\›Ž˜PXT½°pªÚtµOó4ì¥ìy‡s”pÅh#^7Xó4h¨†NÈú '4Û˜=¥Ž_Eš­_€qnBµüÈßê‚FÐEf:pÖA|ødÚM®B1Ùzûšx“'@Oƒo”ê‡Èoí›b>ñ@M $ñ Ú+b TsFCÓŒYެ1êÙ® -¯HNÀoÅ`q÷ªjy–‡¹L¥èœMî8[²¬Ø©mö ~œ]ãœÃ,ä!¨Ý×B e44ikÁÏ1Ø@Ñù­»F<„~@ëC:eh\O }ixkòŒjòâPaÛ“3«¹Í¶¢ºž×ƒ{uarÈ$ô8e…Y*¨n±¥£§yÖ‡ÜÇÈ9×V èÔàB¡wYˆ{&ñ0Lz£~ȉ#ÔJÉêä*Tõ‘Aúau<©ËÌòÆ0%.Eß°ÝFÓlÄh#*ßÈšlƒ&9d¿S^3 “í¡}Ö¤ÐV±ƒ7Ô5èˆüßV}ôZõÛœü‚¬•Ç·°ÒèíuÕh´á„Ƈt2aØÀ„áOfUo¶švõ¦çŒ®ßò¹Ãô)[í´CtÈ“ŒR†Å\œÈ9¶šh¸M4NI,ÍЄµ´öÚ–^Z¹¥ÛîÒ¶C~áº.ýWt6³ß¹\²¥©ñÛ· :]¼ºnýtŽ~Þk¸*ÍÆA³Óè6ZÁqûhgo÷¤½²äèÁ*FgŽ-Vµµ›tÖȽù½:X±†®_b ØÅœºFãf4R¶ÐEŽýAÏV– Öq)šjB qÇ`÷j-cx· /³ýd^ØrK9±]Ú/¯R ½ Ή愓Îü_˜ÄËÂÆñ„z–¾enN^Ôç¶þÃ÷Á¦œ é$=W$ýÇ»ÂûVØÉ‘; ÷å€_õÐÆ&èì´¹¬ŒÙÙL•pÃrÈï;NGZ=Îí“çÀÉö%g¶9¨O'é‡ 2äæíÃDÀ™ ½+9>~Uæ;<ó¼^“XÒ³fRÙñ&%“dö¡¼KÑW‡¾ÿýï€~òÂ$êë_$A8ý9u/¢¤<=—¥€K¶„'Ð8u(ï– fSÓŠåAE'æ²â£Q ªæ$#ÔÛz°¹íîU´UÅq›6!^e([Ñð‚l*/6åºèÑ<éd½òÀpy»{…7Зèg,ýùV®ìƒ„÷Ò(GŠhá¡ä‰ š\5Ì“$\Ô+K²t Â#Î!çPö‰×ÐY^Z]RU£ìÚ¡t•±œZpбF-iÎ:nͽŽ[s­ãÖÂ×Q—¼­Ó—ZðšðšVT ¸šÞß)§,xª.’#ˆŽFÃ;¼n3Â(ž™ª32Á—•1Wæ“©Ž‚£Ó’’ªgh'ã³×iè*"<ëi7¯ð£¬Íç)ý>AÆô¨l›+²»çÜÛsÏ©X}U_’Ì<¾ÙÇæŽk— ÎŽÇõŽ3rØßå‹@~~d]3«ð~öL’e'ÎTÅ;«ú¡à†9»«°Ã:lŒ©³ –˜ÿ­·jÆ$t`8ò6J{‚(Ø CõÒ ·”²ýààQG#ŒmDçi®Š¬¾»©çúF3>V¬ë»·«¸†¼Æ”±VÊ•×êò ˜0ákl;¨ÝÖñHZ¿­ÑùlæS`Gø¶0¨ƒJ9¤ƒçöï¿>#¿7ºæ¥7͸¡óGWô¯:ä Ñ¿²useå–VÞ 3çdé5Ö¸™¶ã×Ô^%]îÙ«]ÿ žn¹Eí"¡ù ÏGîH^Û…ÚÊã|åð²d[†£Š\Žª#GùÉš}ÑÍ£«5×À_h¡[‚ÆœÈsÏk™Ó3 ê·Öz–7„·yü'Èì­ãÓxö€GgÁÒ—W«­µ^üþ_¯ÜïÛ»{­ýHÕįÞûZ®ê_oÿm-ÕÐ×µø/¶Vu4…òj Õ7mò{Ž+±(k:¤!ÑÕ´ kÚ”yä­V»ÆéÒ)¿ Ú{èË bò©kóªb[Q÷,t«ñçËZ™÷sÆÍ‰÷úKî±ÚF5\¥2¿ô’‘ LR CÝ)”!Å tÙFžÍÔ—Áú4ï‘/‚(1˶|Q$\²E"Â?©—•ŠçD4¹2fs/ör›š]&¸;:‘^Tv²ë$Sy6uIÖj¼í(Ö*ä~¡ð(<#C,„gØT/ä™L“gžÁâ%y¦1…gòšz@žiÏp4Çœ<#ÄÑuº!Ù?¶´y@{áoßs̬Ïp5Ö!&Ȩ¢#qŠ©×qj–õR©Æ%³ÃVŽKÙ|`ct&Ímøäv¯®¾j–ݨîÃò—,ÍäÝÁÇùîδ €ý̹Z­£ö!Fè´gÔ n1ßùIìäñ¿W`y¬ø%H+N.wø•5Æ,Ø…ð¸“)Àÿ‹ £8¬§¼Œ‰ÎGp–XÊ`_ösŠfîè¤{|ÒÝßi‹S½ê5W¾$%‡úh(¯l´`ͽÁ(#ɦ®Ñ›˜õœûÄù¼'ÕùΪó_<;s´;»ðífŸa®v%Å"Ü÷±}fË ùžg›3³völ“›±(9lÝ …àÝr‹;e]á!<Ò–M‘UâyÏI¨x~üiù Hu¸Bqªì½Ób¢ÜÐ~z­ g/ö4Š+C©À푺À·›òé¦<Êg:“Ç>_ä?{8½î;9»aÁž)_é>›!5¢îp7\õûašž]1~;¼­Ëì­ýfko‘‡"ŠeözÌ0hÚóM‹Él^ëÍ? n£ÛyZÅÞ™ô&i¾J?›QŸ®>o¡‡—›29K8Ð[…êgµû²Žæu„¿¬ÀŒ…9Z€I+¯Vœ–9J·\Óùöa1ÏP;&Ëà¡ÈË6ÚG_’uD€I§»wü´ $PI8Îg#«°2È«ò ]*kJÚ—è"˜{£s ÆAoªÈé«V‚–9·ñaã×§_‡ÃÞmñ¨æü¿,3ÿªæüsÙ».ÁÈü—óNþÞÏ{­…h¡*¡éÔ¯J<¡ò÷Ð(ÜÓb5Ê?;Go›ÖÓò¢|ÿŸÏŒºÄê”S¢,Yꈘ»*ñ\ከ¼eDölërÜèv÷ÚO½.Ç=Ì×P´.ªÄÔu%e]D_‹_—Ÿ÷vºGíæÿìí>íʰçäâ mÌ2ÓVG—}Œõѽ-~…'6‘{i…Ì¿N[,õ+ý<ÀàAeo÷ÉM´§ÃÝpŒˆ£~X°(™’SÈ©ñ(‹åôù ÷óg¡w¯§*£ÈÔ¥º~DÕ£:{ÉÖi¶~¢|wO.á:Ñèü NÆÅ’N—*#ñdéÇ’|²¿Å¯•Î>⾿.ow÷ŸvI€€üÕ §-zŒ5À™*?ýN˜¼ÅzìsÃÇž¹€”#™ËLo”lMÆŸ›‰"Z–§—LtâäZ×Gž·òè¾3<Ñ3ŒÿÜ;Ÿ= ­À¬†böRމŴÛÎm _NKóTpÝSp-ipDO4§ÒhÝÏ`vØa8 9.æi C.5?ÇÌ™,¢0àS„¿ÎÃ6*ÇÂT¾Ï*ó¹'d3²ó’þsä‡Ä1Oçè Ó=jïÉ€´’K>eÁ|U¼0¿ã5;ºƒY&da/…w˜ñºà™°˜wr“SÖ…Zõÿ{…÷g'}eç:¨=ýØÃÝn@3¡»]„üª&jÅŠõùB¯sMú*5lÿ"ŽúÛÔó³¨é—ÄÜB]§~pª_1>I<ú&>;S‰¨Íº›<€jU¤« Ç’lJãŽ82£3Ââ;"lˬLYZ2ÿ€¿Æ%ŠG*ï倒‚ ɹK0OÝQ»Ûn´‚ÎÉÛöÑIïŸ9#+r%aý•ÒŽqªUŽå@Ϊ*g1À•ÃŒªåU 8QªH¤*Ò¦Êô©œrŽSË5w›»«‚Q§IøžÛiÙ !ù=Ê삉mOò% ‘Sdö è™7[*|/_è;N<>°‡þŒÇþÌ›ÃO?ˆÌQ<âgöD<“3ñŒ§âÏÅ3‘6vþ‡úH`L£_AŸ Á’\©Ð;ÙÚH)3ë ý tA[×·Þxäh—ÀE.a!rr§œ†ýžLW4Nbq”X?öNAxCÿs¤_l‚4ü¸mô»™×¯¾*;OÂà‹8Ha—ÃäƒÍyÕ×§(,'0 ÄM]a‡u_‡‡SDˆ8´[sPØCÍ×C“Þ㈼x˜»%‚–G“¢†ªoäwüpLH— d앪Y¥v¼«¥÷ŽY³>KÍŠ^ó;Òñ•zñ)ÞÓ½Ñ#˜'ͯŽ:]Ò ä+*T÷:ÉÆT&jb ¥ôOà zƒ%ïa6 Ç—BÓrÓ´Ÿà¼Êà–ƒB1½ú@ ÑAµâ©–È‹Z”ÕKš2 ;0ofžnžaVûøh/ŠÖ+Ö£Óô”*¢uÏ^?ÊS–e6¡=ü†öØÔ!üýQ†ÐƒŒ'¥FÀEõ(¦ŽàÛGAþ+ì—Í0­)'®‰¤Ɔ>>x× zây²2ÄëÆUg?Õ˜šñÐÍk͉+œWÎêᮜNÃä®gLnçmc0.Ñ ÌÉ­åfòp*%æÂW–òP¡·w™bUž¥J _ºæu~7Cçw³u~yÛMz£t§* ‡¸¤½A%©²+”%ÍŸÑG-åT_JÄ ­³Ž¢´¿Ê•õ”ÿWël¾Y¸Ñž_².E ²rç7¯B& ¾%U£¿o!”ÛP®‚ë “gûü¸Où§  èéÝH@>kÑòä;å3ä›jùáÉ÷´ËÓŸ©PŠ0Ÿv©nT‹iC8t”§-Sái‹Fi<ô¹å€2C€r°òTÚrk”ÕEJßòKÙ"_bžŸTæ(–¬½S‰²6IsŬ—;é«Våy“…3ͤU<ï‚ÀJ¾Š‹^[yîµk†ÌFùí\”ׂò»Ù(¿›‹òÍ9)g~<¯Óh “µnsìÖºk·¦Êp-49±€¶eñ7ã;£â·Ð¶sé}Y‚Þ—O@ïÂäÉŒ²€K…Äe–-@õ6KÖÛtêm•¬§„?ž²²:™„ûò}W‰Ÿ­tß6Õ³UÚš©’Ø5 »18Øk´NŽ ]A;ð7º‹œ ¿ÆœE?çKaÊçX˜©n Ìx{ŒYyàöø,}æwÇ’î{i<•£þ\·ÆÌ/á[cƒoîs]LH˜«a‚¥ßI44•¸™t-]ÒÝšÄæÀååÍn} ëùºM)2_7ܯw™ó˜Xô3I%þÙ\øouÅX°GìËqÃ|ØrÒ>Ï®%Œ•šó.»ÜÿÙ¦ºXòuÃ3Ñÿ ñO—€£†:Õ>#Ý_B“Ð}Þ øKÅSc¡ÿÿ€‡:ý&öäÕN¢—ýû÷Q…¿W[[ôßׯ^ZÿÅOµ×õ¯jÕ×[/_½zµµùú«j½ Ÿ¿ ª÷ïzúß&ò‚¯ñ>¿Ü´ßy0Uõßÿ?Ø£ˆŸ™Dç ¬vV @¨ðhƒnFý‹aðÝ„?üx•†Iº‘ÆWI󻞇£pòÃÒÑ <þx¬ǽþÇÞ9£¿Kl‘8€E–ÜåAP"<‰@Þ5`Ýñfú •F*0Ü·ƒ»øŠ€Â“p!ô)"Dy×’%:»[‚/®j›HÍËt:¶|Ãã7¸œÞ-eä ¿„¥FÀb”ˆuÙh­£^Z«–a»«ˆ°,@D½ì€õ¸eòC²îy¢ÒoÀ— dðK³ûîè¤4Zïƒ_ív£Õ}¿­òÅ¢©ÀÙ'APGÐì ê÷Ñ–÷Ú;ï |ãmó Ù} 7÷›ÝÖ^§ƒÁ9A#8ƃν‡8>iuö6‚ Ãð’KÓyFË‘`bÛI/¦0Ô÷°x)4pJ¨$ì‡&zíßM_£¥Þ0†"†™ó¶M°˜ùÿ&‰Ú"Ȭޒ^=°EGýJð²Ez£C˜g0åBÌŒ¶AãûÃ8N*ÁÛ7?lÕz­V]¯mVkÁI§±$á½c5-ô`D d[üDtÂÓ«sv%|M—ß©Ìú:ÂŽ¯ÿ‚~ýø_zÑÄ7Áú®£®%d|®œ¿ ¼¹üŒxå}˜ë( “oD92- ùŸ ï(ŠØ}Òü Ö¯=Lëš»³èdj|ôŒ›|B†Àm}rªÖë¨'ˆȳëëÿ{…ø/^IË F‚À„@+:YÓÙmV3=|ö * L1"cþú#’‰&PEýBId*Áop”ÀÈ«Šd%øâR‰–~ÛöÈã€Q+?Š_” ûýº‡BiŒ±ZŠžßªÜ v‡¾ü³¾º¼ÄÀ'~þ»~<:‹ò‘ïU$˜†•ÂIðÿŽ€ïýÚ ÷á²›°ôVݳׯ×Ïú#®Ÿ%í`÷îÇÉ$Aé b¦Ìi# ¢XRmCÌ[àœð¸•; "[`nýeÍ’ËÞú·B¦Sæ:›öeÍàÞªü3›èg½>|‰CAQµ$*m#6Œ5ÑjlD"ÕC6¡VkÖ½•3[dnD‰×ë_D!¥¾Ç·q'Nµ¢ÞуAÞ¿r[ ÚiµÂ3/VrX_É$ŽçbCŒUþ;¥Qs˜dt { ¶"$³.Ä‹¤Kyü© &HŸ8@ª‡·è-8ˆûäýÃ༔ “e2±ÿ®(b?٨ǼI)4³Ý|i€ÕsjI =õ¢/i\$J5±š*ì’D.¦ÜnG‹ñ¥K6È’øéÀøÜ4¿ÿ°±“  ä%†ÀZ–r袼ƒ3úRàŒªÁ7›Þ!#ê¨lØFuÆ.\0iѪ§Ô-?î{áŸí1æ‚C³ˆp¿2¨r&¢!Ç9¨qK.7nж½?$ÆK*•¿Ö”x2kY*%-:YÐ.¾d-¯wÎ f`^?å&lcR¤/Gv‚›•%‚Ê+Ü;ÚºÆÍÀ"‰õ ¿à XÑ#7ó8ËT«êW‘L<)ª´R^p¤•‘¬ÕÓ‚'•‹0çÆÎÐlÎï9ËyQø¶g<#žØ÷f+æ{ÈÕÄZ‡ Eù†þM}↴xWN²…»ð§¬ÈÖo¤Èn2›@¯ý\ÈwC‰BµGSd%¸-ß= ÀPküNê×i™É64¦ÛÖt(pq‘±þ ,ºó§'1Ýóƒ£@´þX² I ]êƒ<¨ÒÙI­ï#ÿ÷Œrîùþz訡xrN@Pˆy¾c±×% rR %TïgFü½®tÄ®³wúm$vxg`â`œŠ½­QÉ®ÿ8uꮼ“Ç¡¯r´Ì*ßßýîY1±°¢öo”€™èR¢3"Šrù³|X,#†óó­ î¥Ü¦”Ú´úa[áѯ?(XÊ&ûSì,™"¬UøOfh/~D¾Ê*PF@ƒÆiwtjK’Dõ/›ã^à ®Ü\û5Xç2 Å€^˜Q 8“|FÄ^Œ²ä=`yqìVâ½} |«n”Ì¡«È[úô ®ÅŸMl8ža™!ÊØá"ØöwJÒTR¶¶U÷ÎFŰȂüÁ£}ǃß–RÁ虢½ô¡fÜô¼..úaUP‹_½êЬOòŽSê,hÙ !‘2ÝŽ"(Äk7®“¹¶P šýfÃÝvJYàm„ B¦ÓÛðÚ‹»Œ‡ÎÐ]_­×A@ž^ŸE·òåHÙ›*À÷Ó0éž](œ dA!bXÇ£ç“@> S>1•üNäæO' MÙCEO:òMêB£š!JXÔoª¨‚Bþ±C̵ÙôDgI {νˆ®m´{2VÚá^&<¶†šmÌžRÇ ¯®Ê7¸ h÷&TËï{/|c`d ·®Æ7{vï<(Õ#'Ü"Ú7Å|þDàâÐ@ߨ ‡T7g44Í‘åtŽuf»6´¼"9Á€&ÁÝ«ás,s™JÑ9›Üq¶dY±SSô†àmüú`$@í¾v)£¡q([ã0»l輆oF'Fú;T³„#q«è]Xiô ´D qφÒ©„av~‡£]]€ìéêM3Ž p‡éC¶ÚiKÔ!Å eXÌʼnœc«‰†ÛDã”ÄÒ MXKk¯m饕[ºí.m;„á®ëÂbrE~¸f§(‘‡­ž«Nä”0À@šÀcL({áê%–€]œŠúT{R}óuàKõ†Ìã*S4iœ˜å‹p8. ƒÅ¼¨0N 4Ѧ]bržÍxËÒh¡-žfé;Pææ$áÅ|në?|l@ñ'é¹"é78~ÜÞ¯ÂN®Ð­Ðñ¾¢î«ÚØä6w5t,B\ÁAcÈ!¿ï4:iõ8S´Ožƒàz™dwè¡‚ y äa[ž(ǧ¯Ê|‡g`ž×kKzÖ¦ã¬J2{‚PÞÀ¥è«Cßÿþw@?yaõMxR&§?‡ îE””§'ð²pÉ–ðüç!~¨ª¶1­8‹o¦qGÏ­¨’‡¿97Nüæ\8ñ› ljÿ<¯mtw½¼´º¤ªFÙµCé:+Æ»XÇ­¹×qk®uÜZø:þEPåå»!ä£Ño+#¬ÛŒ0Šgæ…”ÿ‹¬Ì'!RG§%퉠ºNÙ´Î mÐ^Ø?Ö˰‡]›ÏSú}2‚ŒéŒº^v÷œ{{®â7Ý—Žsoö±¹ãò¥z-€º¯€è]÷Z™NàØ!{&ɲ8 ¹Þ%Í‹¢8†¢g}=žZÿ$ÔLTxŽ¼Òž îÂF Þ@qGÛ_ò¢f!Àˤ¹*N°úëÍøX±n.:;Å1ä5¦ŒµRv¨¼FGqiÂ×”R­v[Ç#iý¶V˜®wj: ¢Æ Rüèà¹ýû¯ÏÈï®yéM3nhÄüÑU‡H¹ç¾ÄqW¶n®¬ÜÒÊ$cäìxc-lemP·[Y=²”Sí9´‹W„æƒ<yáC¾Vç+‡—%Û2Åoýr8ªŽå'köE7®Ö\k¬ß– ±$Ò³§fÔo-̳“~•ü'Èì­ãÓxæ€GgÁÒ—÷÷µÖ‹—ðÿê|{ä|ÝÞÝkuè7ª$~ôÞÖrMÿjûïj©†¾¬¥T]d«êØ å-ÔªoÚä÷EbQÖtHCö-¢«iÖ´)›vXÀk/ØrøXÈí Y{Èí<Ë…Èí™"&r{;ƒÜŽÅK"··§ ·ç5õ€ÈímBnÇ“ÛÜÈí®Ý6\|<Ãï…gü"x& œá™L“gžÁâ%y¦1…gòšz@žiÏp,Çœ<#ÄÑuº!Ù?¶´q@{áoßs„¬Ïl5ÖÕŒ!&Ȥ¢qÚà ˜še½Tªq#`Éì°•ãP6ŸÓI#G›=¹Ý«‹¯še5ªÛ°‚‡ñù  âæŒ3JznδФ7çs­Vë¨}ˆñ9í5ÈÂ2Zqr¹& Š‘<À «PÿW,*Œâ¥ 4fš9Pßßi‹S½êíV¾$%wºÌ(TÍË[aÞ¾`ŒÑ°ö®ßÜ'Îç=§ÎwR‡üâÙ™£ÝûœkÁ â›ã±*Áݸí[n€÷<Ûœ™µ³÷`›ÜŒDÉaëN( ï[Ü)ë @E³~V‰ç=¡âùѧåŸ YÔá E©²ôN‹‰rùém.œ¼ØÏ(. ¥>@ÄÌh¤!Ì®äCMyÏt&}þT,2Ú0sÄ•³ì™ò•î³R#æwƒ™sãþÀOí½}D[Xࡈ"™½~3úØÌvób°™ ò®?–bçô¿¹*]ülÆ|ºú³ðßáÕ&&bÁ-£1_ÿÉõ³Ú}YÇò:Âß  V`ÆÂ-M\\¬Vœ–9F·\Ó‰“ y†Ú)…Û¥=ô3Â>9ʼ91|0ƒ6ÿª Ú¼U{~Äyt­õ†ù€ó¯æ=S6~}úu@…à‚ÙùYfþUÍù瞉ÀÈü—óN>%™›MˆªŠNýªÄ(Â=-V£ü£±sô¶ÙxjTyñÚ¿U^•˜Š*/J> ª¼ÌR°p¤Ë|¨Ëÿ˜ ºüÒ˜ËÿxDÈå<âòÏ{;Ý£vóövŸveØó rq¿6f™i«£Ë>ÆúèÞû©5kZ`!ó¯e°¯ óúÖ*{»Onâ =î†cB8ê€]gKN] §Æ£,–Óç,ÜÏŸ…Þ9¼žªxŒ"S—êúUêìa$"¸Qv»'—pht~'ãbI§K•‘x²ôcI>Ùßâ×J·ŽŽgs[=Øy{  ]jÚZ™¥c­Ìþb_ýzÔÞÝ{ò=u{” ÂÂý$KLßK\òqö÷µøuA û'] 5èÇi …c p¦ÊOÿ4ðöÏØaIÞÒÌ€×À¨í ÇkÈ&Þÿü²å÷n˜Æ0.Ü替0nC–{îßÏ<6 Aé%Ÿ²àF6„jWivÇkv2æDHXvOãó[<óNnrʹP«þ¯ðþ,à¯ì\/€ê–8õ —£X±>_èu]&‚í_ÄQŸb›úqxvõ#ýŽ˜[¨ëÄNõ«dD9×GßÄgg*í´Yw“P­Šd5áX’MIÛ}bþW|E„m™•)CKfÐÁ׸DñHe¹P p!"ÇþQ»Ûn´‚ÎÉÛöÑIïŸ9ÿ*r¥\ý•’ŽqbUòžs¨ÊY på0j@YTʽ r/“¥r‚9N$×Ümî® rDPD&á{n§e§ƒ@c”×ÓØjÄrºD!r RÊ>ƒ=óæF…ïå{blj§öПñØŸy3ö‰à‘7ŠGüÌžˆgr&žñT<ã¹x&’ÄÎÿÌB¿ÿ ŒIó+AxM0ÝÔäJ…ÞÉnÔFJ™YWè¡ ¢~ËQ»«ïE—Èïa¿'““D¥ÑǽSÄÐEˆöë›yýꫲó$¼¾ˆƒv9L>ØœW}}ŠÂr@ÜÔvX÷ux8E„¨Ck°5…=Ô|=4é5ŽÈЇ™["hy4)j¨úF~Ç'Á„tÉ@ÆP©šUjÇ»Zzï˜5ë³Ô¬è5¿#_©÷žâ5Ý=‚y"Ñüúáø¨Ó%½@¾¢Bqÿ¨“lLE (hšHÃÊÃ)9giÚOp^mtr¡˜^= L» +<¦ÝzrZhþõ£ŒÀÂ¥ž2Êk"Pæñoêþþ(CèÁÆ“R#à¢zSGðí£ŒÀמ2.š7aZ›P¤5‘’ …´æ¢®:û©ÆÔhÄÑÙðÕ ¡Lyœ~˜Ý íUÙÙ±rsrgèün¶Îó°Y‹ ÒÞ ’TÙÊ’æÏ糚ƒ›ð¥D¼PÐ:çh1&u µ³ëÊq£u\Š@e;LƒÏTÈä¼·¤êÃãÍ»ù§  èáÝH@>kÑòä;å3ä›jùáÉ÷´ËÓŸ©ð¸õ¢+Ä|CGyÚ2¶h”Æ3L›[þ(3(+O¥-·FY]¤ôý§Å¡sˌŒµw*1Õ&i®˜-‹ð]8™ÑlÈóVñ¼ ‚|ïyì€\3d6Êo碼þ”ßÍFùÝ\”oÎI9ó»àyDK˜¬uó ˜c·Ö]»5U†k¡É‰´-‹¿ß Ô¿…¶KïËô¾|z&Of”\š(-³lª·Y²Þ¦So«d=%,øñ”•ÓÉ$Ü—í»Jül%û¶©ž­ÒÖL•Ä®YØÁÁ^£ur\è š Ýü^ S6ÇÂüKu`ÆÛcFo_øíñY4úÌïŽ 0í{]Oå¨?×­1óË_øÖØà›û\Îæj„`©ÆwûL¥m&]KW„t·&‘9pyy³[_ãÂz¾nSŠ…Ì× ÷ë]&Â<&ýLR‰6þ[…@]1ìûrÜ0¶œ¤Ï³k c¥æ¼Ë.·Áö…©.–|ÝðLôB´Ó¥ਡN´ÿ&X[[[º„&¡ú¼7ð—0ЧF>ÿò‡ÀˆC~»y¶á‹Ûþ"ú¨Âß«­-úïëW/­ÿâ§Úfí«ZõõÖËW¯^mm¾þªZ‡ÿ{õUP]DçÓþ®0±|ň÷ùå¦ý΃©ªÿþ‡üÁ®EüÌ$:¿õµ³J€B•€Gt“0ê_ ƒï&üáÇ«4LÒ4¾Jú˜ïõ<Ü…“–ŽáñÇó`=8îõ?öÎý]bÄÉl´ä.ãIò®ëŽwÕg¨FRá¾ÜÅWž„ƒá OÙ šÈÛw5ÑÙÝ|q…PÛ¤ê@Ž^¦Ó±åî¿ÁP†àôn)ƒ hùí Œ( 1£Œ¬ËDkõÒ Ø@° ä]E„e’ êmd¬Ç5(“¤ÍpÏ ˜†x'¾%ƒ_šÝwG'Ý ÑzüÒh·­îûm•?ÎF ¢;‚foPã&ˆè°t¸×Þyåo›Íî{LÀ¹ßì¶ö: × Á1}vè…ÄñIûø¨³·†—\*˜Î3ZŽÝNzÑ0…¡¾‡ÅK¤á€“D%a?Œ0ñkÔÊønú-õ†101ÌĘ·m‚@$€›$"¨‹ ³zKzõÀ:õ7*ÁËé>ažÁ¸ 1WÚ~tïã8©ocPåPü°TëµZu½¶Y­'Æ’„÷ŽÖ´ÐŒù0mñÑ9O¯ÎU –ð>]~~§2ëë;¾þ êüõ_àéEoß뻎—ñ9rZ|i|F´ò>Ìt”„É7TŠ €ÀH`î'Ã;Jª"vž4FƒõkOïÅÝrW…LI¶÷žq§O¸OCNÙzõ!qv}ý¯¢pÿÅˉ`¹Áˆ˜hE§"«`b»ÍJ`&*ƒoÀ2$”3FäŽÂ_D"Ѫ¨_(L%ø ƒõO‘¶¿C|*ÑÒo;À^\ c°ò£ø^‰·ß¯{(ŠÆ³¥¨ù­Ê`gèékÀ?ë«ËK "ñîûñè,ÊÇ»WaLž0ï-äúïîþѯÝò.¸ FoÕ={ýzý¬?âúY0ì öì~œL”É l`œ6ÒÉ Š%Ù6äM1ŽÀi]¹³ ²æÖ_Öìx±ì­ P:e°³i_ÖÌí­Ê?³©~ÖëóÈ—8$J¢¢Ò&1"ÄX­&ÀÆ%"h=dj¸F Ü[™³EG”s½þER||#'ÑâT+ê==æý+·±› “V+<ørÕ(‡õ5™Höçx06ÄXå¿S5‡KF—Ѱ—`+BëB ³H”ÇŸš‚ô‰Õ¨zx‹ž(Ð}ƒ¸O^`1 žÁK©&Yû/áŠ"”uŒ[´€`ûÕ€§çô’~êÅ9^ÒÈH˜*ÿõ®b7U, & [L¹‹~\ ÄqjB.‰Æç¦ù½ø‡…œ¬ZÓ@É"àR΀(nƒŽâ,`RC=MÝp§bá9Ë.ZyàÎØ™‹)­C]õ<ûA¤åÇ}/ ´ ‹ÍÞ!‚ˀ͙@s(ç€É-iÔ¸|8¹5Ýöþ?,© ÿ:ŠSÂÈtf©½è}Aóø’ѵ¼n;/Æy/•›ÉI‘NÙ îbÔˆ-¯àð`hëN‹$Ö7ü˜€'`EÜLð,s°ª_EŽñ¤¨ÒJ=xÁ!XFWO vU.ð4c(;#¶I”¿ó `ί.]Ý W˜†R¿NôQ9ÌÒÄR•>¿h©ðÄÒÚ‚3zîÐÔÇ¥"ÏûƆB,*Ÿ‡ïZÂϼW3?ekÔ îáÌ!·L\¼!a…Q†(pé^îcÂ\Os6æ5aLjr½Bôæº\¥Øuêêä˜è²5ÓbNñÞæøn¥çTA™‹ÈE‰_0aTåp,çEÁÞžñŒdxbߛƘ/(W €lJ2åëú7õ‰Òâ]U8ÉN쟲"[?*"»mÈlÂÂöKp!ß 5©5E®ÒÈ s[Ô{t«èUà‚Æñù] Gcj¹mM’‚Yí¯ÀÚ;Ñ {"1Õ=?8ºD«’% ´”Ô¥jÈ3 ²Ôú>òÏ8èžï¯‡ŽFÚ‰G òH…˜ç;–€=Ð"o¥ÐVB+ðÖv€ÆßÛ)M§ð:ÛHáãFb#‰·&RÆáìÑû•X‘SVçáòÊ{{ªñrG‹¯òýÝï.“+jÿðF˜É0%ž0C%¢T—?ËÇÇ2ª8?'«à^ÊJéO«¶5Týúƒ®l²‡ÅΤ![Õˆe†öbLäk¯½4h,y§¶$ °dsÜÀ œÁ5¡k¿ë\t¢Ð 3ò§`’ψ؋QVa»Nz—ca‹á„†oø¥yMòõY@ÿðË$±ÁJp«nÌ¡«è\úô ®ÅŸMô8ža™EÊç" ÷wJÒ”eª§l~+"œíŠý`eùS€OÁ†0 æ€é úÑoAjFL€Áñ"$ÖÕúõÐ ½®Èú$oC¥ƒ–­`)ÙíxƒB\wãâ™k Å ™p6|nW¬”èáÚ>da?ý· ý¸k{è ÝøÕzÄäéÕùY<…"NJàT߆ÁÎýìL@Ùà\5 ë:=Ÿò©ò™©4 pf7ñxÌ à TkÊ@*zü‘ocZÙ QÂÄ6xSÅòL`®Í¦'ŽK\E3Èñe,tÁÄ‹hQáœÑV¼'·¥fÎck8¡ÙÆì)u,üêª|­«yoBµü>PøÂ×F^që}Ó¹‘÷΃2`òÈ[Dû¦˜ÏŸ„Hâ‘êæŒ†¦™$²œÎÆÎl׆–W$' &¸{uÈ|Žýa.S):g“;Ζ,+vj ©Þü¡sŸÃ,ä)¨Ý×.C e44Nik÷ÍòàðuéÄ(€§Ð"ÞS¢¶g]5ô¥á®É3¥ÉC…mWάF6[Œ*\A{ FöCð\øxIu+PçBV*H()@~—-($µPÝ„h<è&Vu V•{½ƒ¯–sÛSâRÕ®ÚhšmDåYSØ`oaÇ{›ñ‚Ç«IqÁãi«@©Büx]]¡ >ù’¸mô.¬ò…2ª"FNh|H/†LØ=ŽvuƧ«7ml9J•PÀ¦{Ùj§-ñ‰c€”a1'rŽ­&nSK34a-­½¶¥—Vnéwâ,è¥å™1ÞÜà (¡k5j“e#{n(Áƒ³ÈÐL!‡,,Xä¤kvŠ’‡ØŠ¾êDk SŽ « °†j¬«…™˜ äA*²8¸š©¶ªr1nbõÚÓã…S4ilšå‹p8.FƒÅ¼H4N ¦Ñ¦]¢€žÍx£ÓL¢Ÿžfé;0 ÌI«ÿÜÖø>Ø4 éOÒsEÒop¹+¸É‰P¡­^!gAEyòW=”±éº?mîj¨ZÕ‚ í?~ß9ht:Òzr&hŸü`ªœ~™t@è¡‚¨(ÂÄ" RÎe*óž¨yV¯I¼é9›Žë*Éì BY”¢¯}ÿûßýä…IÔ7áP™ œþ‚ºQRžžÀËPÀ#[Âhœ«øi¬ôÄ´â,F½™8]¢J.ýæÜ¸ô›sáÒo.—þóDضÑäõòÒê’Êe×e묘òb·æ^Ç­¹ÖqkáëøA±—/•ŽFC¼Œ°n3Â(ž™Ãþ/²2Ÿ„Huºt~);e·Òº0C™òGX?Ö[´‡]›ÏSú}2¢ŒéŒº^v÷œ{{®âCÝ·•soö±¹ãò%—5B\öªÀÞuï«é$²‡“ìºÓëÝYâ9Ó¼¸ó 6zÖ×ãñõOBÍD¡‡áÈ»-íQ¢02 4°ç Ôx´ýðí0aâ¼üAš«â$¬o‚ê¹>ÖŒ¯ëæ¢ÁS€D^cÊX+e‡Êûyq¤—f |MÊÚm¶õÛZa‚੉ï0HƒU9¢¤ƒçÿï¿>#ÿ9ºø¥WθïóGW&"ÉŸûöÇ]Ùº¹²rK+¯’ŒÆs°ê5¶ÐœµAÝ \4gõ¬SNµSäÐ."\šò|í…O[yœ¯g–lËp¿.Ìá¨:r”Ÿ¬ÙÝ<¸Zs­Ñ…[‚Æ’ØÒžv˜apP¿µ<ÀÒNÂWòà °×O7âœHŸ`kmåÛ/W_¼\ûöE½úb¥¾ö-~S‡oVñz:0Šþ¿C. ÿåÂÿï¾ÅÛ»{­Ž¸í•¼÷ÄÜ¢Ÿ3ü·ÄTC_S"1²kuÔ†òPÖq(µ‚xý-Ò _›DÊ9¦Å"±éЈ<_D`Ó¦°i“8#:²@_ þæð±æø"æy– æ3EL€ùv`‹—˜oO˜ÏkêæÛ0ǽ¹æª¼míøx†K< Ï(ÀúEðLÏ8Ã3™"&Ï42<ƒÅKòLc Ïä5õ€<Ó žáp’9yFˆ£ëtC²~li‹‚öÂß¾çx]Ÿ­k¬1ê&CLF§è´‡·'05Ëz©TãFÌ”Ùa+Çm¾õ1:“–‘¶•r»W·n5ËÔTWqï÷ó±#ĵ'¾ô\Ûi³¡IOãçZ­ÖQûC„Ú3jñ<¦Ây´âär'M”"¾Tˆ„%%4åËò^—§YY›Qw2XûþN+XœþT¯ÃòÅ!9Òeö¢j^Ž óÖ£”$¯¹Ænn`aÖcî“ÉóžPç;£ÎC~ñìÌÑî}ÀÔµkà±Ôñ@‹xqÜŒöY-7f|ž½ÊÌÚÙ{°jƲä°u'ZÞ»$þŽSÖEôÑÉZ4ëg5qÞ{*žÅZþE’E®P´+»¾Ay´˜(÷m½ú…3{ÅE¡TªÀˆÎ4\úÑ•| *ð™ÎäqÏŸöEÆ+f·rvÂ=S¾Ò}6CjDíán0ó{Üdª½·È <ÙPD´×c`SßÚŽ‡^ tAŽ÷Åhçéh[œj8oKülFºö;fü¿ÃKMLú‚[FãËþ“ëgÁ¸–u4°#ü­€Â`f,ÌÑÙ$ÉÅjÅi™£|Ë5]¤©g¨RaÚ7?#Ôá“#ÚøÓMd{ ioÕ›×ÝiVÜkÿjÞ#Ñaã×§_'Rahͼš6ÿªæüsO°G`äNþËy'ŸRÙÍ&> •ÅV§~%â ²¿‡.áž«KþÑØ9zÛl<5v½È%P€]¯JLÅ®%»^æ@X8žæ?> lçL…vþGidç<"°ó? ×ùç½îQ»ù?{»O»2츹8È_³Ì´ÕÑec}toƒ¼ýÔš5-°ù×2Û…¬ýk€G”½Ý'7qÐ’wÃ1 !õ µ³%§.SãQËéóîçÏBï^OU ùÌcÃ&”^ò) ndR¨fЛfw¼f'cN†…!50gvÁ³`1ïä&§| µêÿ·…7g'eçz 8­‡j¢ÆÑ5XŸ¯òtà²ÈfÞN’žJ(Û‡W—ò97A_ª ŒÓN‰Ü•{? ÿ÷ŠÎ´vç›Lµ*é·*÷N£aƒÓ=÷`1®™§•-wsµò² œ Ó‰HöT úgÅä´õ*gReîÞAxŽÉŠ(¨ÛÌÖkLêkl¢edâ°–¹0©¬ Êœ.´€Â4Ù?jwÛVÐ9yÛ>:éâå:¦°ÅmEYk¥¼lœ›ö]Eµr˜"§Ÿ•ƒ ;)ï,gŸå„²"á¬H/+ÓÌr>N·×Ümî® zDÈG}Ûȇ,ódH¬6Jxƒ€5è;±Ñ‘“÷ ä™7ƒ,|/OL¢D¼£€OΘŸñ Ÿysr"«ô™=Ïä <ã)xÆsðLäÕÿÙˆ~ÏÚA*°%£ ²öäJEÊn”H™}Wè‡àæ zÅ8¹‰ƒqœ¦Fß'Fj |Ÿ‚m§ê¹b¿|µ^{c0á°ÞÕ¤ç1GõªyóÕ”¨øÏ‘~¾v Šâ㶦‰àï|TäP ³½Ñ­ÍæÕÇG.‰hrÛJëû‡~dJ`?+”DV0i̹HÓ~‚shÑ ñêQpÙMá)¸ìÖ‹Ï2Èò¯eõ”!PR+S‡ð÷GBF0ž”Õ£˜:‚oe&šö”pѼ+×Ä­‰Œ9°£5vtÕÙO5¦FCŒÎ¨^ˆ]Êãôãê΀e¯ÊÎŽ›;Cçw³užÆZLvÌ”¤Ê®P–42ՠج€/%â…²Ô D¿)¡ÎÃvv]9nôÂŒK¨ôø4œñL…L.{Kª><À¼ûŽ~ÚŠÞÝ×]ôä³-O¾S>C¾©–žüq/Áyyú3¨^t…à.pò*O[¦ÂÒÒx†isË?e†åˆá©´åÖ(«‹”¾ÿ´88nù ¿X²öN%dœÉóÄlYHïÂÉŒfƒš·Šçùêó»ç±rÍÙ(¿‹òúCP~7åwsQ¾9'åÌï‚çu+a²Ö̓`ŽÝZwíÖT®…&'ж,þf|'ÐPüÚv.½/KÐûò è]˜<™Qpi¢P@±Ì²¨ÞfÉz›N½­’õ”°àLVJ%“p_Òî*ñ³•³Û¦z¶J[3U»faÎûƒ½Fëä¸Ð4«ù3¼Ÿ¥dŠ…éêF*ÿ/r®}á¹gÑè3¿Æ5гïu;•£þ\¸Ì/á \ƒoîssKp˜õ`‚¥ßIL3•}™t-]ôÑØÀååÍn} ëùºMÉ 2_7ܯw™ó˜Xô3I%þÙ\øo0uV°Gì{jÃ|Ør2.Ï®%Œ•šóZ¹ÜÿÙ1ºXòuÃ3Ñÿ aM—€£†:_þ›`mmméš„>èóÞhÀ_Â(žØüË_©?àÄ¡N¿‰Ý,ØIoлÚè/ *ü½ÚÚ¢ÿ¾~õÒúoµV{U­o~U«¾ÞzùêÕ«­Í×_UëÕÍÍW_Õô=õï øÁWŒxŸ_nÚïUþSÿýùƒmÀ™It~úmg•€ƒ*6è&aÔ¿ßMøÃWi˜¤i|•ô1ëy¸1 '?, ÂãçÁzpÜëì3ú»Ä‰“qÉ]Ô%®“(ä]Ö_“ž¡žI†ûvp_`x"†>Eƒˆð¾!Àyèãn ¾¸BÐmÒ… h/ÓéØò wŒßàÕ|pz·”A4‚üvF”&¡‹QˆÖe¢µ Œzi  XÝ®"Ö²Cõ6²ÖãHxÉ ¨fà牆3HCÙ•%(üÒì¾;:éÖûà—F»Ýhußo«ü®h]p¶Hí4{ƒ&Áh‚È K‡{íwP¾ñ¶yÐì¾Ç™ûÍnk¯ÓÁ¸“ ãÙh‡^3Ÿ´:{AÐa\É¥‚é<£åH0HfÒ‹†) õ=,^ $ œ) ûa„‰Y{ wÆwÓ×h©7Œ¡ˆa&Ƽmfê¿I"‚´2«·¤WÌ×Q£¼¬A‘Þèãæ¬¿Ó’íGgÐøþ0Ž“Jð6]ÅAµ^«U×k›ÕZpÒi,I ïX N Õ‘“Ù?ƒðô A~ÓöE*ÜS—ß©Ìú:¯ÿ‚FÁú/ð¿ô¢7ˆo‚õ]GÃKðø<9-~@œsùËû0ÕQ&ßp±3ÙŒøvö¡øZþ»ÿ»üŠH.^’fl°~í!«=í^²JÒÓ3B( …ÁiÈ Y¯£ž VÕ®¯ÿïUNà¿x÷,O¢þ6°4A>` •çòmðóJðã¿zýJðœ.ðàŸÏãÑs0=åAðÖ‡AÔ+?VÄoÕ þþSлרPb;hb÷——vDbÚ÷ãÑY”i¯B—4`<áÚ&:ýwiÿƒ Ïn¹ WÌœ·êž½~½~Öqý,ˆò»q?N& J[#Ñ(tÚH'ƒ(–dÛg3µ`8§|‰3QU$2So<‰™Åšh56²ã!7Ù±‚vÎj‘%X¯…”z_ªI¼7ÕŠzÕ6yÿÊml"h›U•ïŸE± (& ¹þ Ùʆ·ü!¥À?l&.#ô©« 1h"éIž‹Ô¤O Éš`3á-:¤@à â>9ƒÅx6/¥2dyK[AbÜ;PÆ´)+A»±Û81ðç9c#ELzŒ—4ÒÇRʽ«X@L SI‚ÓGh‚{ùGcGþ ?ŸOð³*Øè²|VŒÏ'øYUèèž)”ÓÄh?Ÿ›æ÷üc¸mTY‘ˆr’Ea«4é1Vi»!'º©iéèXFvßÞÁV]øiï©WÌ7-?î{Q¢í1åbH³Ã‰€Â20t&AÍ90sKO.hnð¹½?$ÆK*g¿ó–À2MY*E::tР¾dÜ-¯'ЋZ`^uåfhcR¤ßHv‚¢U%ÂÐ+ <ÚºÈÀ"‰õ ?à XÑ#7³/Ë©êW‘5<)ª´R^pT—‘bÕÓ‚“• LßÎXnÿïI¨Êõ Ñ›ëÅ•~e×O¬“^¢ØLw9Å!œã–ÎXu.‚!%"Á„ñ–ñœˆ{Æ3’á‰}oŽa¾ó\-€¸UøÉP”o|èßÔ'nH‹wUá$[8± ÊŠl²—÷A•Ù»ûï½B›ýZ,ÏóêJ‘¾ ™#óˆîE{—óUÆ$d{èÖ ß¹ süZÄ«r6KBÆ\ÆâÀ¬LAjó=TKIåR^½,XÁÌ©b¡dÊ«™Å)šyTÍ"•Í,êf…3‹Ê¹Ò¹Ÿ:¡M¨¯)ï§P¨±7ŒrÄ*–Eœ€p¹+p0ì÷ð .Oét/•ê­ÍOüÖo¢ÔÀ]¾Ù蘡D?’έËlp($°•ÎÕ¯DG†=I i¾Üû’îঃ(iJgÒ™3iM3o©–ß„ŽÝC Jž|WŒk¨K .° ¤á”¡p%\‚G;ô3KkçÆar¦“h¡r~$݌ף›)2 téÓËøu¡^¦´]®NÎôâ&µò¿°’p%Ô5„Ô}Õi``áFÀÜfÀb YLEó™‹5f3 f3 f3 ²†Á¥µù¦X÷³ Hèmw_뀚ÛVMÍ4ŸÁ8Åîn5y1Ôî¶[ÂŒ?ã!‹ô e·°­© ¤BŒÛx5J£óųL`mÃ3iíÛ?8ç},0Z^»ħ†5o|OØ2+?ïX âà=ßGþï“IÎ÷×ÃÀ¾ÍÙ‰G`¸ ÈV1ÏwlÇõ@m ,¡`…òb·¸c‹öÞ†ù‰òÔ—êØžŠ7(({éàq®7ö,Jà$IÉ[Ò°c±1´¼é£Këi›´4Ü[ãú»ßÓäRÔþá=]™1‹ŒDSà*Kù³LË'¥F>N‘à^Â"H êÓ9†¿’ª&1Õdd£ËÀ¬@ Ãa†ö¢¨ÛÞ9êhÐ ¥ZiŠ-I‚ Ù7ðgp ÛÚ¯Á:—sC è…ù §`’ψ؋Q•&»‹z—ca>ŽÇI|+0½±œ_Ÿô?JÞ $6X nU¸9tõXž>}ƒkñgÇЖðˆP¾à[¼Ʋ,÷ÕªggbãXÄ@þ¸ÑåqoˆS_ÁÀ¹s"ãˆèCÍx—c°¹x– ‚ÖÓõÐóÌbyÕ1g Å -[¾¤8·ßüD—¹o8TãÄüT[hÍy–Ë&×Ù~&ñxŒ±7-âÈ8“¿qò½b 5RIlI¯‹” ˆ¿mÁŸÿ·œ5õ°rAOg 3Œ”­Öë O¯ÎÏÐD¹&ÅnÊ1Ž @?›„£zP 8Ï=ôeÍn¡à+J1$Á¿TÖÐ0 Í<Œ*ê2å…-JÀ2çMC›–𠼩Þò}04×fÓó–R<Á©jÃIP(º!á¤ò‹m%ås¶Õü3¥V ë8¡ÙÆì)uNJÕU™4U 0ÎM¨–ù[ÅB›7yA €=ë!˦ó*Æ;JëÃÌ£yí›b>ñäO $ñz’”êæŒ†¦Ù!²œ†%d¶kCË+’ H^ܽªZžÑa.S):g“;Ζ,+vjFb?%øCá}¼ød€Ú}u¤Œ†ÆaxÅ~`[|Dçd:ýð4ÿA¼¹&·:-‚ëk§/ {žýL~x*lûâgµ¬ÙLTO†´³sd§ôÄK ‹TPÝb#GOó®øE¸]ÿË«…ë«J`õrVHV¯Uý@ÉWU‚LLˆ ÕÑÛ\3Dµ ÎO‰K1lÓn£i6b´•odM¶AŒ²S,¯™žz è¡OxÖ¤ÐVRã^Ò» ¡|ª_Œ(4ÕªA‚Vý¶‘‡PžÈ $­Œ|fh«÷’L6B¡•ÖâèFNa9)5˜Lã¡[r9q9ùÀõo¢úN‹HÀ¸ÍÆAþ3á¸p†b6Tn(—Êå¡Çâ´’3– *xŸ¯K&Óö,Ú„òÞNÉûÈÑÀ®ŽÏH­ê"C¯¬LÙN 6­pkµÓ– èj¿‚ðgí'’õ­&nSÒ34aí8{Ë•ÞqRÒ¾~%ÈäÌè,»ç0C áùq5J€Åx¦¶šj»›·B;…;wa9tF³S”ãØ6ÀªÎKVab‰¨-n/Ȇ·Ä] §S‘ÿÜÊ’qôe³µÕUÆ7ÚçÖ¼‡ãpÙXÌ •íÔÐi ]Ú ™–çœhÆ0w*ÿ&±¼Ö7Óªà,}æš9Iøê)·õ¾6P‚“ô\‘ô0ï>¬]¹ Ts®.ý7YÏ ‹“e~a¦ÅH á¢^Qâ÷£ªØ·ÀzyiuIé²k‡Âõì*¡:ZnйU-iÎ:nͽŽ[s­ãÖÂ×±8Îæ‡r ^ñŠ|Rö»šÞßébYðT]$Gü¡²†+Ôu›Fñ̼P‘ ¾¬Œ¹2Ÿ„Hu‡u®xºézh‹¿õÒ ¿£²ý0±"aò²ßúAš«â,¬ïåê¹ÎïŒëúbdG• ¯1e¬•²Cet¶ðµH3¾¦#eí¶Ž‡Ûúm­Èl*ˆ&¨À2ŽRì àû¯Ïèbï^¤»Tmû@ÎÝe Ì71’»²useå–Vî>ùX9²= Æ7Óv|ãšÚ«äB¤‹[{µëÌö4ÕN‘C»ˆpjh>È»)Ì«ÖÊã|åÑ´d[†£8õZGÕ‘£üd;èæÉÕšëHÁ•´9-ÐÕŒˆ\÷·Ã ƒƒú­µžå ˜Š<1ÈìŽåÓH!ƒ'gÁÒYÛZ[i½h½x½Öz±¹öúÅæê‹z•|¦Ft¾@§Û‹Vç°ñëÚÁ”¥²<5)*xïé¹5?/øo驆¾¦'\²duÔŒr¯Ô_¬¼^¯­~S_…qȘ¿µV‰5…@$8Ú!¸éPŒ<_DnÓ¦·iìÑEø(í½ôÉå=õixóú*ƒÙ‡]™[ÅËË;[ã6­“¢¶Q¥tR—ù¡"¹+ÐdÙ’bº€%o7¦û ´À#’Qb–m‘¤â}He‹E„sT/+ÏyêŠNe{Ù›ÛÔìbĉtáòÅ‹H1•G”d­ÆÛŽb­Bžiœ¦Å3ÜÕ‚x†­ûBžÉ1y¦‘á™ü(Ål¸ãžÉkêy¦A<ÃÁ=sòŒG×é†düØÒí…¿}ÏÁÝ>[×XcÔM†˜ ;ŒNÑ)> ©YÖK¥7"ØÌ[9NhÝ_ÅìLZFÚVÊí^]‡Ö,SSÝ‘$7ÍǸ÷©Œ ä¹OÕfC“ò†ÎµZ­£ö!lͨAŽ;lÀ. \9ûÏHlU àÿŠ…‡Q¼FñLsytÒ=>éîï´‚Å)cŽZÚïòe+yåežøj^6bócÑ$㺖snÌhÖýîðówç;ðÎC~ñìÌÑîìâ¸ëIuC#T,^àÎ^rv@N*y6>3kgïÁ¶½±”ÃÖP˜ Þ- ·¸SÖ':-¶fý¬ZÏ{EÅó”Ë¿B²¨Ã df?:h¢VÑS~yØi).¥ž6ÏGêªáŸ0<”jÛ`ŽLdz¼ÈÉœå|‡»¨|¥ûlÔˆÖÄýaæV.{/m©ì#úëNþîuH˜‘ós¢2w3Áïæmáƒàk>–òg˜·ÕJŽ?›Ñ®†oÁaàïLåË~PçjÛPý¬¾7[9êÀ÷ܯ²uÅŠÆi™£»Ë5] ¿g¨“e4ĬÃ6Úõ_’uDØJ§»wü´ $üZI8Îg#«°;0~hMIþsï]ôÖYIúØõnέ{Øøõéçþ°w[<婢˜s >mæUÍùgpßÁðM» dÎÉ'‘Ùg¡ú húÔ¯><Ï*î¡E¸§Åj‘4vŽÞ6­§åE•,—u ¥NDÌlM‡2»1çx(ß ôtĪé©£f[ÛEÍè·Î”ýj¨P¹eÀì¼õ‰›ë2Þ:Ÿ ðâ£5Õ zg,gBÌÛóS¸Vϧh…°ñ!õ{oü’é£M{å^æ,9ïi2»ñ¬ŒrfÈþÿ^KØ®!¢LV)82*¤›Âý«Ö®ŒRŸm7ºÝ½öSïâã&i.ÚŪÄê,YÊÝsßu}-~]~ÞÛéµ›ÿ³·û´+ÃþsТƒüµ1ËL[]ö1ÖG÷¶ø:öÔvXZp†â_µÎã µí{)ü"ÓÃs¨µ¨¾Îšp„õèYÏ3 EÎe¼!dC€cç m®ó§ìËÅœeøS*C•­”"Ô¥D Rb’Åocô†ìíÎx¦rÒÊå0†›šnÕó†wdã>:÷¥3xü‰ðƬã£(ê¥Àû1¥“ùN'n£r‘¥‡ÜôÞc¡þ,LÃë©¶ŽQdš:UEC›ªÎF™vš­Ÿ'éÉ•j¶æl…båªKM]%£ô£,”Ñßâ×JúŽŽgó¥?˜pÃé^@.5m­ÌÒ±Vf±¯~=jïî=ùžº=Jaá~’%¦ï%.ù8ûˆûZüº¼ÝÝÚ%òWƒ~œ¶Pè1Ögªüô;á®Ò¸þœQÅÕ¹a°p¼Yx°ð,êóçÞœJãLðÏÓæÏÎ|ó ÏrÏ}°Ãó™ÇFÓ.½äSÜHîSU®€ùo†²“1'<÷¢’"ì4)µ #Â’ˆÊÿ­J „ÌüAvªL%›Â‡K56å¢L’ï`Láè4Lαø%¯.)·^ã¸|øZ4}ˆ·Š Nu¾Œÿ½¡l"á8uëÓ­ÌëÂú£ðf‚¬à@%2w¬ÈwwÛ ¬ºínºtu{CDiLz„ˆbZW‘`O¦u‚ÝIéF®Æn‹”š¨e´h%â‡Bƒð6¨¹Ù6u/]¢rš¨ç7ñªd›ùM¼v›0¸A߃%³t~çÖþ»[ûgZél<¬9 âtÍo§Ô¬çÕ¬U3LÔfX´sj«ãÖ-Á ¹uën]ýP KÂ9ר¼äöÚÝv£tNÞ¶NºLE0‘ ¬ò×Êû a?¾«ÐóŠw'hGDk$(GqdøFEW€çÿ !72f#£5‚T@pFBh$ÌE†ddüEÃH x)Ïns·¹»*HÕ©-¿Qؤ2U–0zë Ô¹ÍEÃ|bù™w¾—õØáÎÂ[¼ÙƒOï*âÑ?xFCEŸyQÁ°MÓ3|ùL¡^ÚU4T V!¤‘gûò™Â½´«è\Éâ)3ÇFÀ?ì%A~'?pºãgœ×ø™@¸œÿ5¤~¦ Œ¸áe‰ªÉ• v—Ý( òÆ^¡„Óï¥a°¾õÆct­[…$£€6K¥Kf¤=à§ ¡?nMnæ5iäJÂ`¯8Ha¼Â9誯OöXNà«‹ð–Âë¾§©5“ÐZÿBêçœj¾šôVäÆäx´<š5T}#¿ã§øк4·òƒJÕ¬R;à¦Ô[ЬYŸ¥fE%$„#(ò·lJ(Õ7šüyüÔ~ƒåø¨Ó%C…œ—ù6ËBb3³‘‡…i0ùÈÁú§a½Á€P–{˜ Ê0 í'¡¾ BT(Í´ ñ¤o° ¢Ï ¶eÿBK³Ü ”QJã.7ˆ—2±³JB„ aTn¯e=ÄxRj\t¶A¼~”A$á¿Â~¹ApÑÙñ÷GâÆŸ”ÅÁI@…Çqʘðo¦âÛÇE4‚–Ëɧ8¹ùæ´×ÿ¸Zê4l¸ƒ~J6%sÕDP€¡,ŽÞu‚žÈ;£ŒW‘¶bÕ‘Õ5&hïü%Œâ«/?ཱིXâ›Ø ór£ÿ>ªð÷jk‹þûúÕKë¿ÕZíåë×õ¯jÕ×[/_½zµµùú«j½ºµùò« zÿ®§ÿ]a\Y|Õ½ˆ/{i~¹i¿WùOý÷?ä„ÃN<¾K¢ó Ћ;«„jZ x´A7 £þÅ0ønÂ~¼JÃ$ÝH㫤˜çáÆ(œü°t4?žëÁq¯ÿ±wÎÑcð0N`ü%wy€_”¼9îOz×áÒRƒïÇI|žô.é-jª4>›Üô’p;¸‹¯‚~ÃD(¤è3CDŸ"-:»[‚/®FƒãÀ@\_¦2 ï§ÖIðS8  à¬¤¨Dýp'$î¿Á8žàôn ‹“žìˆÞvžˆÞˆ 2`£P_]v Z«À¨—VÀ€‚åó‹U òN@‚‰zÙëqaž5jóŸÖÐc˜ÂôJCŒY‡¿4»ïŽNºA£õ>ø¥Ñn7ZÝ÷Û ã­A A³7hLŒ&ˆ_¶t¸×Þyåo›Íî{L¿ßì¶ö: – Á1ž©vè]ÛñIûø¨³·œKÓyFË‘ ä Sê{X¼HøvöÃÁ z ½ÆwÓ×h©7Œ¡ˆa&ƼmóëéI%¸I"v 2«·¤WÌÞQ£¼¬A‘Þèãæ¬ÆSóîGgÐøþ0Ž“Jð6‹Š6‚j½V«®×6«µà¤Ó@5‰¦O7.AC÷¤ŽÈ9‚l‹ŸˆÎAxzu*>M1šQ¸µ.?¿S™õu¸Áú/hZ¬ÿÿK/zƒø&Xßuì„àŸ\5WN‹_àõ9¼Àç‹^”„É7¢Ü™lH|=ûÐ|-ÿÝÿ]~EÄ/I8X¿öVŽ"‹|?a%)ê¡3ƒ†v\G=A/K˜àÿ½ŠÂ üïi‚åIÔß¶&ì3|œ»ò\ư<¯?Rôâsºl„>GÏÁˆ¤ÁÛ 2íe°ò#¦ýV êà?õ]ƒ ex†6&qy‰øF}¼°¾ëÇ£³è|ãâá\qž2~UE;0…ù¸ƒpÒß@CS7‚“Ë-dA–ÂEÓõS»îÙë×ëgý×Ï€8Ô°%÷ãƒÑƒdI4 6ÒÉ Š%Ù6äÁN­ŽÀik¹³ rPçÖ_ÖÍ÷O;;¿7ºÝöï'­“ÎÞ®3&÷W5FöWhn*Û„É&8l {Ic^çƒa¯]Ó5Šï‡ÄøaIÁWéi‰Á%Óë¦R¨Óã˜ÚBëu$z¼Ì›²ÜüÂLŠt<ÉNP8 ¶¼X`hë+‹$Ö7üvŒ'`EÜ"‘XêW “UZ©/8Í@ð´`‡yê…wmO”*ØXb”sº†:Ò¢œ.“…{Ž{üFöWË¿í@F®Y×tÎYaC©ß€á×ü°>Â7Lkû&Bo"žp©è.`cCÁq–Ï}-±_ˆË¢Ÿ²¨Œj÷pæ[&.™×ÂC°ät ª4÷íx®ï;›I‹o^_@e¤7× ,ÝÒ®›YçB'²™QhŠ?9Ç›,¯:8XÊñÄᛜkBÚøžBÌ‹zYuÆ3’á‰}/Ü_™®æòD \¼X”/ŒèßÔ'nH‹wUá$[8± ÊŠlý৬ÈÞÝïÚ¬è×byžWWŠôÉt™Gt/BØ»œo¥`„n­×;Hè }-Âk9 ;®Ïa=\\zµûÄ®¿Ÿj)©\Ê«—+˜9UÌ"”Ly5³8E3ªY¤²™EÝÌ¢pfQ9÷Q:÷S'´ õ-çý 5Vâ‚RŽX…‰+p4ì÷ð¨.ÏétÉ•ê­Ý‡W—£õ›(U3 î‹³Á5C *;[—ÙáPH€`-аUJtdØ“”@‘æËÅš’t;+¬°[uÂåA”Ž”ú3éÌ™´¦™¿NËo|¤8é!f;O¾+Æ5ê»~ä(Áø´¦Z ‰æÑÎúmmYíÜ8,PÎt-TΤ›ñvâqt³Ê ]úô2~]¨—)“3½xfž:X2Eé !u_õ_Ú˜ÅX¸0·°C`S`‘ÆÀ|æÀb ‚ÙL‚ÙŒ‚ÙÌ‚¬apim¾)–ÁýlEàI³YÔܶjl**’°´–Áîn5y1Ôî¶[ÂŒ?ã!‹ô e”Ü{[SA8…$„Ðüj”Fç# k™ÀÚ†gÒÚ·pÎúX`´¼v=ˆO kÞøž3V~Þ±@„Ñ{¾üß'“œï¯‡}›³ÀpcP9ÏwlÇõ@m ÜA¡`Í”`fˆ6.Ú{¤2ÊO`\j¨c»J¡‰ƒ»H‘3_‹Å©²(»Ôš=¶cXb# —7}ti½Œ“–†{oÔŒg=›‹W=° h=]=¯4–WsÆP¼Ð²õ^LŠsûÉPt™ûD5NÌOµ…6Мg§êš„牛 Kd¿âxG– ¶ Nää{Åj<¤’Ø’^:ÐEØÈ^þ[Κz—¹ —7ÐÌVëu§Wçgh ¢\“b7åPGú§a0›„ãzP 8¯EôeÍn¡ð+ʶ%jUé0 Í<Â~fçjÌI3çMŠüR^ƒ7Õ¢Bþ±†æÚlzžbŠ·%8Um8 E7ì¥êÁ·ˆ“ò9Ûjþ·R+tBVU8¡ÙÆì)uNJÕU‰ƒÇªG"ÑósàImÞDä%01à¡­W1›Îï<(­#0æy´oŠùÄ“?5Ä7êESª›3šf‡ÈrT›Ù® -¯HN¶6b ÁîÕ9rŒs™JÑ9›Üq¶dY±c¦ñU‚?‹eècOÖ1¨Ý×qw@Êhh†×øMí¶ÅGtN¦ÓQOóÄ“mr«Ó"¸¾vúÒð·çÙÏ䇧¶/~VËzI$–•v®rvŽìܦžˆIa‘ ª[läèi¶òìæ<0°ZÀ=Ý.†n" Ñ›ÃI< áØÏJ­”¬Nátª>r"fЄêèí® ¯MÅè§Ä¥¸i·Ñ41ÚˆÊ7²&Û  ¦ºìËk¦§žz(ž5)´U Ô¸—ô.C(Ÿê‡# Nµêc U¿N®0(“R ‹yá HSÝ‚‘ýØ nõ^’ÉF$š^ÝÈ),'å•“Y@tKN#'N#' ¸þM4@ßi ¦®ì8L€7g(fCå†r©\z,N+9cÉ¡‚7ñõ»d2mÏ¢M(ï-(/·¸ ìêøÕª.rÊÊÊ8š¢MkÜZí´CœGÒ¬b¿‚ðgí'’õ­&nSÒ34aí8{Ë•ÞqRÒ¾~%ÈäÌiya†@‹÷Ôjò…¯ÝVÛݽí*ܺ ˱ À”š¢¬÷¶VuÞÅ {”pÂylf#J\C{ NEê`àp+ßHÆÓ—Í.÷Re¨óx¡}~Í‹p8Ö „¹„XÌ GèÔЙ]Ú/¯R…Á<ÌÄ( GÁÿ…I,ïõÍ´,8Kß½fN¾~Êmý‡ïƒM#–à$=W$ý'Ì»EZèM n÷ 9o*ê2hÕC› 9æ ŽÕào^ìHßí“_È€š`!9p“*è¬ÆÀ©:©úˆVrî™T™ïÐÃÁózM"NÏšIe'£kGfOÊ }uèûßÿè /L¢¾þE„ÓŸCP÷"JÊÓxY ¸dKøu#/':Äl*bZ±<‹jd‚²ãE¨bœØÞ¤ÞÖƒÍmw¯âqÄI©¨†kSù¸°©ì•åjro°Ö7}ÉÒÆòîëêѕ›‚7çò²ßTÉ“e~fV Ü”‹–„6ÍÚ²ïõòÒê’Úe×¥ëÙUBt´à “«ZÒœuÜš{·æZÇ­…¯cq&ÍåÜ´ÂTMïïôJ±,xª.’#ˆŽFC¼=Œ°n3Â(ž™ª32Á—•1Wæ“©Ž‚£±F˜ »ÎSöø­ C0”àÂþ±2}=ìÚ|žÒO>ÀøÉžÁè ëewϹ·çꑼ›¹n®ñÍ>6w\>\DãY–‘O˜W2À€Á­0hr²`‡ì|&ËNœÏŠw–<˜À{ðnÏúzœñþI¨“ÐáÈ»Fíì£Ç¶øú[/­ð<*Û33¢&¯û­¤¹*NÃúf®žëþθѱ®/J@vT òSÆZ);TÆg o‹4O •µÛ:oë·µBlË©Ð7˜©ƒÈ8N±ƒ>€ï¿>£« ¼}‘Sµí9t›%@…Üõ²Rñœ7Ÿ®€à4¹¹¹MÍ. ÜíH÷,_ªèí$SyvxIÖj¼í(Ö*䙯iúX<Ã]-ˆgØn/ä™L“gžÉ@̆2Nᙼ¦gÄ3¸3'ÏqtnHöÁ-m+Ð^øÛ÷¸í³b5F­cˆ ²°è|œâ£œše½Tªq#:Íì°•ã_ÖýUÌΤͣ­ ÜîÕUgÍ2"ÕýgAÞÓ|@sqWÊEž»Rm4)¹è\«Õ:jR0ÖŒdá ó­8¹ÜÁè0#Û–åEóÂÏ[Õø¿báa/H?Ó\tOºû;­`qʘ#’öû£|ÙJþv™B¾š—¨Ø¼žÁ83ɸ®Mœšu¬ûü¼Ùù޲ó_<;s´;»8îzR?ÝÀÐÈÓ‹G¸³—œ“&cžÏÌÚÙ{°moF#å°u'&ƒw È-î”uʼnΘ­Y?«Öó^Û#5"1q˜I˜¥‡|~üÔöÞ>¢R/ðàD¡í^WƒOd¾i±ÛÍ{À‘},åψs«• ~6#] ˆÂwx*_íƒ:WÛ†êgõ½ñÊQ¾WÞ~½ÅÊ+V4N˹]®é‚Üù…Û.>nt»{í§ÞÅÇ=LÁ\´‹U‰Õ)Y²”»ç¾ë"úZüºü¼·Ó=j7ÿgo÷iW†ýç Eùkc–™¶:ºìc¬îmñ+tí©í°´à Å¿jÇjÛ÷RxÜH˯m¦i»9+ËàÛ«ó}øE&QÔ¢þ:£Thʺ£g½½€&9ý“ñ@-Ž‹7Ô¹ÖÌŸ²ÏsÖáO© U~¶RšP—~-HYG¿Ñ²·;ã¡ÊÉ—ÃnÞ¹UÏÝ‘ é\˜Îà>ðg¹Sø³Ž“¢¨—÷Ç”Næ;ž¸ÊE–.rÓ x…þù³°u¯§;F‘iúT} uª:{mÚi¶~",¤'תØšW°е«.5u•ŒÒ²PF‹_+é<8:žÍ™þ`^Àa<§»¹Ô´µ2K?ÆZ™ý=ľúõ¨½»÷ä{êö(„…ûI–˜¾—¸äãì#îkñëòvwÿi—È_ úqÚB@¡ÇXœ©òÓïD²JãúsFW熀Äñjá€Ä³ˆÐŸ”xs*3!ŠOc˜? 8óÍ_P<Ë=sâŠOaw»ô’OYp#sOU¹æ¿ÊNÆœ@Þ‹Jx°Ó8@4Ô‚lK",ÿ·*e2“Ùy<0Ol .ÕØ”kˆÒD¾ƒ1…£Ó09Çâ—¼N¸¤ÜzóákÑô!^+‚:Õ¹0ø†R…„ãÔ­O×2¯ ë› ¾Ÿ‚•H˱"ŸÔqp34°ê¶»éÒÕí} „1éàaˆ9[Eöh\<™³ v'å¹»-RÞ¡–Ñ¢•õ‡ß ÂÛ æ¦ÒÔM¼t‰Êi¢žßÄ«’Mlæ7ñÚmÂà} –ÌÒù[ûïníŸi ¤·ñ°ædÓ5¿R³žW³VÍ0HP›I`ÑÎa¨­Ž[·ƒæÖ­»uõ$(, çD¢ò^Ø?jwÛVÐ9yÛ>:éb4ƒ@‚´BØÇ_+ï+„ìø®B$(​‘€¢‘Áa:*„ËȈŒŒÅb¡ ‘p‘ÑÈ"¥×¥,ºÍÝæîª U'®üFaÊDXÂ^èM¬KPç´íòHæg^\Eø^>Ãc§;Ëoñ">½«ˆ‡#üàM }æEýÂ"4Qϲå3…jiWÑP$X…Dž lËg ×Ò®¢s!‹‡Êÿ°–<ùüÀ錟qÞâgÁrþ·Žú6ð>ƒW@šE$­&W*à]v£”@Ê{{…~vL¿—†ÁúÖ еn’pŒjx -•^™‘v‚Ÿ‚’þ¸m4¹™×¤‘O( o€Áâ …=ó G¡«¾>Üc9£.B\ ;¬û:œ¦ÔLBký ©¢sz¨ùzhÒkW‘S“ßEÐòhRÔPõüŽÚO@ñÒÜÊ{ *U³JíPD‚›*PoB³f}–š•pN¡Èß²)¡WßhòçqUûm–ã£N—lò_æ›- ‰ÏÌF¦¹äSod蟆ôÂQîa¢'ÃBb|´Ÿ„úŽLˆQ¡76?Ð*4Äqõ&°«Šr¢JSW¾i Œ¼™¬gˆ%n»4ìEÑÚÊÊç¾Á‚B`ˆ<ƒØz”Aü ÍrƒPv)»Ü ^>Ê ÄÎ*5 f$„Q¹Q¼z”Qô`ãI©ApÑÙñúQ‘„ÿ ûåÁEgÄßeˆ |Rj'Ç)£¾¿™>ŠogÑZ.'Ÿâäæ›Ó^ÿãh©Ót²áB¸(•”xÐUq†²8>x× z"«Œ2_ERŠUGVט ñÐ…Àá|cNr•oEΨáb¨g\ <ÔÛÆ` \Æ¢˜–[i#˜PTJL‡¯,¥¡¢Boï2Ū%-–ä½SLÞ&²ÿç‰u/96üƒ6ò&3 gšI«xÞ¬À+^[yîMŒÄ³g6Êo碼þ”ßÍFùÝ\”oÎI9ó»àymU˜ÈuÓ©‘c'×];9U†r¡‰‹´íŒ¿ß G¿E¸KïËô¾|z&Of”\š(°³³lª·Y²Þ¦So«d=%,Œpç?<„ûªÄÏ&°Iõl•¶fª$vÍÂndö­“ãB·æÎ0ì®Æ"u<Ƈ‚1ÇßÏ9è†Ò~&ê¬x`3Fç ìîEEçœE£Ï<6GrÂ}ƒr¦rÔŸ+*‡ùå/•cðÍœá8ßh[Ìá5ÁNï$¢»B !MKaø2E ôáÒòF7¾Ä%Í|Ù¦¤[Η ûË]îÚø¥Ñn7ZÝ÷Û*µ=ª+OÑA³7¨eF®Z:Ük#ò·Íƒf÷=æßov[{Ràízót|Ò>>êìmA‡Ú— ¦óŒ–#Áü“^4La¨ïañR ùôˆ7 ûa„9é{ ÖÆwÓ×h©7Œ¡ˆa&ƼmóËÚI%¸I"Bô 2«·¤Wì¡Q£¼¬A‘Þèãæ̉ó¶îGgÐøþ0Ž“Jð6UÅAµ^«U×k›ÕZpÒi üD؃KÝ=)™#:5#Ûâ'¢sž^ƒìOSŒtþŽËÀïTf}$n°þ êœõ_àéEoß뻎 þÉUóä´ø¾WŸÃÛ |¾èEI˜|ÃÅÎd3âÛA؇fàkùïþïò+"¸xIÚEÁúµ‡¬RôX´{É*IOψ§ è+§!碿Žz‚Z–&0¹ÿ{…ø/:ïƒåIÔß–&¼+|´¹ò\6<¯?RHÛsº‚>GÏÁ²”ÁÛÀ“…Ô+?LÖoÕ þþSÐ]Ô¨Pæ_hb÷——smÔG'vð]?Eç?‡‹ˆþ“a*n€©ÕÈï„“þºœZn!Ór®˜®ŸÚuÏ^¿^?ë¸~–Ćݸ'£$ F¢Qè´‘NQ,)ȶ!}µ`8§4ásgAä&έ¿¬9ìbÙ[ÿ£Ž9Dצ}Ys¢·*ÿÌFàY¯Ï#§ ¢ªH$HA<‰–Κh56Þ%A6#7Q« £²á:Džh”`½þEê¾g•(Ī’c¢JªÆV@ ‚¶YU ƒ)Ë€Q›Ð8·¢{ –­lˆqËRš LÅfÒè2Â#¨ººCy“žä¹HMØjúÄ‘| 6Þ¢‡4Ü î“wQ ‰góR*C–·´–pue“UÁ°¸)+Aûh·ÑY™ñ¢RZc0Ác®5é£Ìéÿ+ŸÊ¼7¾ÇHaõ¯w ’²b¡KÊvE¼,÷G±ü½þ(eù3GséÝý_eiü¨Z¡ Yþ^±³¢?Ëå;šŒK¶,ÅÆç¦ù=ÿØ ަå‚ú£w•k ëUèSFãJÀ‰œå:45-ýËÈîÛ;F«ÎÊž ÎnAEÃÔ@{?íìüÞèvÛ¿Ÿ´N:{»\g ÜýI/rîOï +îÔäéñTV3Æî;0—’‡ˆm† È¥‡  "Êÿñ{Œ Ã3Ÿ‹ö†wk~7íáëýÂñò˜¦ ˆ@f3ÐÒ&¬4ÁG;ÐÑK#:ÑÒ¨{ˆYÆSœc±ëT1Òbo&ûÑÁnž¿äÜCUÔ•Òün5yoÖî¶[ÂŒ?ã!‹ô e”/{[SAØ$„ üj”Fç#ŠšÀÚ†gÒÚ·pÎúX`´¼v=ˆO kÞøžÐ3V~Þ±@„¥{¾üß'“œï¯‡}›³ÀpãDûržïØŽëÚX~BÁšY¶Ìg\´÷6ðc”ÿ¤Þ¸ÔPÇv••,w‘rf"@³0„³OQ¾¦5 $ lÇP¿F€+oúèÒzi&- ÷Î}†þî÷R!ZµxOW&@ … #ÑvƒÊRþ,SŸJ©‘\)¸—! ²úÁtŽá¯¤ªIL5Y Ùè‚0+P°F˜¡W$§˜&E±í£î¥î ¥)¶$ 0TdsÜÀ œÁ5lk¿ë\Ì 1 æ» œ‚I>#b/FYTšì.ê]Ž…ù8'1æXâަ“ãë³€þG¹„ÄÃ+Á­ŠÐ6‡®ÞÊÓ§ï`p-þì:0Ã}Ê\ð‹çñϸS–¥â:_õììQlk€È7£<î qê+8wNDc}¨Ïd 6¯d`AÐzºz^=,¯:挡x¡eëý•çöœè2÷I…jœ˜Ÿj m 9ÏN}5 Ï7³”È&ű6Ž,A¼œÈÉ÷Š-ÔxH%±%½.2&t -ŠN’½ü·œ5õÎqA/Y 3Œ3®Öë O¯ÎÏÐD¹&ÅnÊ¢1›„c¢P 8¯/ôeÍn¡Ð5Ê^%Á_Ufæ0 Íø#<Â~be§?ÌIÁ2çMŠüR^ƒ7Õ“œBþ±†æÚlzž6Š·8Um8 E7ì¥êµˆ1ó9Ûjþ·’R+tBVU8¡ÙÆì)uNJÕU‰-ǪG¢üÐsnàIInÞDä%1 —­W&›Î“ï<(­#0æy´oŠùÄ“?5Ä7ê…Pª›3šf‡Èr¨šÙ® -¯HN¶6ÂöÀîÕ9rŒs™JÑ9›Üq¶dY±cfÆU‚?‹ècOÖ1¨Ý×1‹@Êhh†×øê¶ÅGtN¦ÓQOóÄhr«Ó"¸¾vúÒð·ë/#]2Ϩ&ç<¶ô³šÛK"«4~•td§õ„  3UPÝbËGϽ•Ï6籆Õ†:êFpõ0ùŠöMâa'Ç~ȸQjùdu ATõ‘=1M%TGHpMÀhê½CJ¬‹‘°vM³£¨|#k² š`JTËž²¼fz꽞‡"<öY“BûJ{Iï2„ò©~Ä1¢h_«>VZõÛáä c!)e¯8¦.¬ÀÕ-Y†ÍhaïÍ™lDBéÅÑœÂrRò6™jC·ä4râ4rBƒëßDt¨‘ ðàÊŽÃRs†b6Tn(—Ê¢Çâ´’3– *àŸ˜K&ÓF.Šò2ƒò_‹KÊÑÀ®Ž>­ê"q«¬Œ£)Ú´fà²ÕN;Äy$u+ö+hVIq"Yßj¢á6Ñ8%2CÖŽ³·\é'%í;á,Q‚LÎŒ‘ûfÄ>¿× FÓ/í¦Úîæm‡ÐNáÎ]XYÔì%—·­²ªóöTØÝ£„“zÈ£4Vâj‚¸ ät*Òóƒ[9=2Þ¿l·ÄÆœî뼇cý—‹ü‡Å¼¨N ½Ð¥ýò*EìÌuL|Êqü_˜Äò®ßL}‚³ôØpæ$áC²ÜÖø>Ø4â NÒsEÒopê¼ûPðFˆžáf¯?§¢î‡V=¤ÙðŒc¾óX þæEhôÍÐ>¹ŠlúÕä€À£ÉuôPAÇ7Æ'Õy+Ðm´’sõ¤Ê|‡NžÖkpzÒL*;!Øaƒ<2{‚P¥è«Cßÿþw@?yaõõ/’ œþ‚ºQRžžÀËQÀ$[ÂÕkœ‚9—  fSÓŠåñTk ûï†DãÁ&(õ¶ln»[O(NÖB}B0Ü^›Êí…Meo¹(’{©µ¾éËG6–×aV®Ü,·9÷™…(¢Jœ,ó£½R¢\´$€hœ•}5¬——V—”Þ(»v(\Ï®zó¤åfÕ’æ¬ãÖÜë¸5×:n-|‹“Õl~(·àl¬¥jz§7Ÿe9ÀSu‘AóG\·ÇMeä®lÝ\Y¹¥•»O¾ÿŽl‚±ÆÍ´߸¦ö*¹é6×^í:³=MµSäÐ."œšònF sŸµò8_y4-Ù–á(N–ÃQuä(?Y³/ºyrµæ:R8B-AcN t_#ÂÙýí0Ãà ~k­gyÃA$O r»cùt#²òàÉYðtÖ¶ÖVZ/ðÿj[«/êUr—¿¡×ðúÛ^ìÕTjAòÞÕs þ¥÷ßÔS }UOè d¸êÈån)Bíoˆ,ùG YD5ª‹HjÚ45m¢¥m^SeÐtÛá°+óS«¸xy7kÜš¢OÔ6ª”ÔDª'?ì.wÊ #XRL«C­äÀƤ(2Í…>Ó{¤Œ J̲-eT\‰˜l‘C£ˆðwêe¥â9ï?]ÉÀYr/us›š]2¸û:‘^Y¾KÑûI"¦òlí’¬ÕxÛQ¬UÈ3Óô±x†»ZϰÁ^È3™"&Ï42<“˜ kœÂ3yM= Ï4ˆg8ˆgNžâè:Ýìƒ[ÚH ½ð·ï9ˆÛg¾kŒêÆdZÑÁ8Å@85Ëz©TãF¤šÙa+ǯ¬û«˜IcG›?¹Ý«Κe=ªkÏ‚œ¢ùxá⊔ñäÀ¬Ù4ÈÂ1Ü[qr¹C‘b F*¶Ë‹æEw·ªðÅÂÃ(^ ï}¦¹<:éŸt÷wZÁâ”1G'í÷Gù²•í2={5/ °y-ƒ1g’q]c8764ëQ÷ øyO°óaç!¿xvæhwvqÜõ¤Ðº¡‘‹),pg/9; 'eÆ<Ÿ™µ³÷`ÛÞŒLÊaëN(Lï[Ü)ëŠZ³~V­ç½~¢âùÈåßú YÔá ,³k4Q«èI ¿°ˆFì‡÷‰RO €ç#u{ðO˜ ž Êpm0G¦ãY^ÞdŽÃr¾Ã‚]T¾Ò}¶GjDeâþ0K×øüؤí½}}^àÁ‰Âܽ>3B~N„ûn&Èݼ|ˆÖÇRþŒæ¶ZÉ‘âg3*ØÕðˆÖ{‡× ò?¨sµm¨~Vߪuà{ñí× YºbEã´ÌQÜåš.ÈK_È3ÔŽÉ2xpò²öæ—d‰Òéî?-ØÔùldv†­)É_¢ñ`8+ÖH»Þ͹u¿>ýÜ ðüyWÄœ3Àé‡3¯jÎ?ë—ˆ4æ€oÚ!sN>ávÌ&8 ÕEͧ~õáy>q-Â=-V‹ü£±sô¶Ùh=-/ªD_¹Ì¨K(u"Â`k::Ù-Çk=ùÖ §ƒPÍàMÛÚ.jF¿i¦¬õWCì.c`ç­5ˆ¡ë2f~훜@ù$×z(½3Œ‚Ã$¢wÂÌBôzÚ4îK—ây7Âý¬Ø4>ª~ï LC2(³ioÚËœ(ç=Sf·Ÿ•?ÎŒ%ÀÿßkÛ5$J“É0G3S¸‹ÕÚ•Qí³íåãF·»×~ê½|ÜÄÖE{Y•Xâ÷‘%K9}î».¢¯Å¯ËÏ{;Ý£vóövŸveØ‹ºt¿6f™i«£Ë>ÆúèÞ¿B‡ ОÚK NRü«Ö|üR¡¶}/µÇ´¶çÒysV–ïíÕù>ü"Sés µ¨¾Îhšp̕ݳÞ]@‹œÊx1ÈæÅ:]«çOÙwŠ9Ëð§T†*a[)E¨K?ˆ¤4$‹ßÆèÙÛñdå$‘Ëa 7ݪçÅîÈ]tnMgð!øÓÞ)€WÇSQÔKdJ'óQÜFå"K?¹é ¼ÇBÿüY˜:‡×Sm£È4uªŠ>†6U=Œ2í4[?¦Ô“+ÕlÍ+Ø ÅÊU—šºJFéGY(£¿Å¯•ôÏæQ0Wà0‡Ó}\jÚZ™¥c­Ìþb_ýzÔÞÝ{ò=u{” ÂÂý$KLßK\òqö÷µøuy»»ÿ´Kä¯ý8m! Ðc¬ÎTùéwâX¥qý9Cz«sà HÝx¿ðHÝYÈåÏ«»9•Æ™ »§1ÌŸ ±›ùæ/ŒØåž9»§0 l]zɧ,¸‘ʧª\óße'cN¤ìEe;Øi ªlAª1ïtùQ­r=^~°‡è/Açé×úª{C¹<±x´ ëÓ½äk£¾‘׳G}•ý£‡ggQ?ÒùtKu—£%} V¬þù[ûïníŸ)ÂY’qXsR‘éšßN©Y·jrÕý£v·Ýh“·í£“.†Å,"0¢þZy_!€Ãw t§ÈeÂ/DLB,d¨BR() ð W!(B!døAXYD$ÈAdŒA¸‚”2•2£6w›»«‚TŒð…Å)ó ‘ß›X×XÎ=–ˆåªåû÷W`´«Á%l·y`ø_Em™¾)çbM^«y]S„uªâ‡b‰sñ'ŸÁæ~æÅêÃý tÃäs.öÞ²$/»àÓ»Šx‡À‘åÏ$Âd`µ«¥°­×34ùL¬ŸI©€ÁdÔØ AX<˜“ÏÞ¤]E'áÏaù2þ!à&y€ò;ùóè>ㄹϲäü/êôS_ÐRç] ÂÛh‚ù$'W*ºZv£„MÊûx…~ú²ßKÃ`}ëG×t-v<…ùi€Ryúigë)(ƒÛF“›yM9k’ð¸/Rs0¯`r_õõ!Ë ØsOQØaÝ×á4!ªfZë_HUÓCÍ×C“ÞTŠd¶˜u-‚–G“¢†ªoäwüœ{LH•¤¿œJÕ¬R;´CÝuZR˜5ë³Ô¬¨LwpÚAþ–M‰Ño4ùó¸Dýºñø¨Ó%H~²Bõxÿ`Àl¨[a~E¶ny#Cÿ4¬ 7øq³ FºV'¶OûI¨ïb„¬g­VÛü@«Ðï!„Ì IEÉ8¥I%ÐÆëûÌÛû3Äÿ¶Îö¢èw™VÖ€ô CtàÄÖ£ â_xßUnêjŒÆ]n/ebg•…P»B•Å«GE1ž”m¯eIø¯°_n\t¶AüýQpîÀ'¥FqpPáqœ2Tû›é£øöqF årò)Nn¾9íõ?n€–:M'î Ä‘•‰×C5qÿl(‹ãƒw 'r—([¤>Xudu ]ìÎjå¤@QY=äŒGÙzæ(ËC½m Â5)zi¹•6‚‰1A¥ÄtøÊR²#*ôö.S¬Ê³T tŒ¼Îïfèün¶Î}€ôÎ¥ íe-I•]¡,iþlj)§¥ÌaùYǾã«\;‚дM“MË< 7Úó++¤ZRFiîüæUÈ 7YšÎp©ùB¹ãå*¸.fé3ËÞ1mEá uW=<ùl¡•'ß)Ÿ!ß4ùžüq/ÁCYyú320ͽ‡€Ô£¥©€¥ša¬CËÀ)Ÿ¥ßPÊH¾!°ù=ÔÔäÖ(«û”‰ñÉ/Õ‹îòî;ä»ÅbIÞ;Åa"í|žX÷’cãhÓ!o2£p¦™´Šç]ôYùÿqÅk«3Ͻ ΗcöÌFùí\”ׂò»Ù(¿›‹òÍ9)g~<¯sz ¹n:5rìäºk'§ÊP.4q±€¶ñ7ã;è··sé}Y‚Þ—O@ïÂäÉŒ²€K…ït–-@õ6KÖÛtêm•¬§„…Vû‡‡päL•øÙ£5©ž­ÒÖL•Ä®YØÍßÁ^£ur\èÖ܆½ÑÕXä'ç›LXþ9wPréÂtuˆjÆ(:¼¨(³hô™Ç€HN¸oðÇTŽúsE0¿ü…£? ¾™3ìCbªb¨Avj|'¡ÄiZ À—–7ºñ%.iæË6exr¾lØ_îr׿A"ÿG’Cü£¹Ôß:àW*@ `WØa-†Á°å€NÌ®Œµ™3 ¥Ü–þÙ`¾XòuÃ3ÑOìµt\4ÔPNo‚µµµ¥Khú Ï{£ £øêAþ`gôýMìâV¤áÕ0¼Ýèß¿*ü½ÚÚ¢ÿ¾~õÒúoµV{ùzóõWµêë­—¯^½Ú‚ÏÕzõå«úWAõþ]Oÿ»BÌ øª{_öÒürÓ~¯òŸúïÈpáN<¾K¢ó À;«„ËX x´A7 £þÅ0ønÂ~¼JÃ$ÝH㫤 ÔÏÃQ8ùaéh<Öƒã^ÿc’$d[œ ÀÊHîòЉ(Ó,ƒŸ/-u1 xœÄçIï’¢HLã³ÉM/ ·ƒ»ø*è÷0aä‹N1,'šÈ@Ø;ÑÙÝ|q5„rá2•]?µN‚ŸÂQ˜Ç Ž£~põØâ0Ü1~ƒ#ÁéÝ'ܽ3p6½„åõ‡B)ë²ÑZF½´š–!å«@åÀ/õ6²ÖãH`ø |.@AL00@”†ž°„ivßtƒFë}ðK£Ýn´ºï·UBvTœÞDQÍÞ ÖMliép¯½óÊ7Þ6šÝ÷˜Ñz¿Ùmíu:<4‚c4Þwè­ÎñIûø¨³·†_*˜Î3ZŽƒ¦&½h˜ÂPßÃâ¥@ÒpÀoO“°F˜I½br|7}–zÊfbÌÛ6¿T‚›$"ª ³zKzõÀ¾õ7*ÁËé>ažÁ< 1éè~tïã8©ocPMPü°TëµZu½¶Y­'ÊcÔ±Ý8¸UГ’>¢S8²-~":áéÕ9è’4…}‘ ÿÉåGàw*³¾7XÿuØú/ð¿ô¢7ˆo‚õ]G!ÿ䪹rZüri|o'ðù¢%aò(w&_Â>4_Ë÷—_±ÀÇKÒÒ Ö¯=„•£È"ßOXIŠzFŒa6¡@8 9‹úuÔô²D þß«(œÀñB XžDým`kj‡+Ïe°ÄóJð#Ñ=§[-øçóxô¬%Az¼õá;1ùÁÊ„ðô[5¨€ÿÔôA5*”»Ú˜Äýå%F õÑ3|×GgÑùÆÅ‹#âe@§ «`r0r¦᤿n'—[È4‚,…‹¦ë§vݳׯ×Ïú#®Ÿ%‘taKîÇÉ$A‘ ²$…NédÅ’‚lò¡V Gà4€ç‚ÜYÙusë/k»XöÖ¿ €Û8Ó«Mû²æEoUþ™-˳^ŸGN»þ"D}‘Èüúñ$F@5k¢ÕØ@@ŒìD­Žc`h#MˆLÇ(Æzý‹($À|Œ)1uU+*ÎÇ„CT­€T•³ªRÞÒy£(6¡Q[E!÷”-[Ùã–?¤4’‹Í¤Ñe„çZ!zu!¦&eÉs‘š Ìô‰Ãl&¼E· ¨¹AÜ'—¥Ïæ¥Ôˆ,ti+,áê"<&¦[Ö¡¨¼++Agïä`ï×U‘Ý!Ç)-3F?²ãZ“>Êœô¿bL«üÇ{ã{Œ’VÿzW±Ð+0¢lWér~Ëßë":—?S„®*édЏŒÏ2—+ttÇ~má,ŠŒÏMó{þ‡1pŽÇå‚ú£˜•. Û€ð8å˜wXOy³iήîb§"±v×ÚjrvM„ï,ª;­ÔÓ¸±pûÔÍO;;¿7ºÝöï'­“ÎÞ®3P÷W5pö›h ØÄ&h_ÖwIã÷æû®]“;ß÷Cbü°¤ xt ®Ä’yES)óÑ3f÷%jzZ^0"óÆ&7±*“" ²”¨LáP|­€‰ahë÷ ‹$Ö7zϰ¢Gn"0È$éêW’UZ©/8ÊH³îiÁeò@q /š¦(t$H«Ä[æ # Û¢%=]j 7÷øì¯–ïuÏBÊÊ+œ›˜òÂGIkûæ>A¯!p©È'½±¡ ˧Ž–8q/Ä¥ÅOY„95ƒ{8sÈ-XIˆsaª!ðk:M›û\6×›MžrMàHû ¨|€à®3RºG]w§N¥‚ÎL3‰Ê¿fŽWSº¢;=9/Â%ЦSü¿˜õ çŒg$Ãû^œ¾º[Íå‰@¹±(_\п©OÜïªÂI¶pbþ”ÙúYJY‘½»ÿÞ+´Y1ЯÅò<¯®é ’é02è^„°w9ßÊ:ÝZQú;Hè }-Â<9ý4®Ïñ \Œm4ü¾ª¥¤r)¯^¬`æT1‹P2åÕÌâÍ<ªf‘Êfu3‹Â™EåÜGéÜOÐ&Ô·m÷S(ÔX‰‹29b’aäV«ÀɱßÓ¼<ÆÓeKª·v?^]ŽÖo¢TÍ€º·Ìy %¨¡ìtn]f „C!‚µ@ãõ(Ñ‘aOREš/dGÒ]´|¥c#—øL:s&­i¦ìÒòËMzˆ?Í“ïŠq`­ÛÉ,é|˜S†¸—Ií¬ßx–ÕÎÃåLÇÓBåüHº//G7«DxÐ¥O/ã×…z™Rݹ:9Ó‹7[&äÞÂÎ(Êøf©ûªÿÒÀ,&À€¹Í€Å³˜‹4æ3kÌfÌfÌfd ƒKkóM± îg (B™Í: æ¶UcSá`2ÐåØgø6vj\ØeÆ6ú".î'.j‹ÅÛ«¶ íUû ¶Wísß^m†»ÛdF;¹¿¦MV×ô‰–FÝCÌ2Ö(˜â‹]§X‘{Û0Ùvó ø¥Àº|)¸yŸZ÷¹:‘Ͷ»í–°ëOãxÈ2%½BÏ%8ÞÖdbI%†o¾¥ÑùˆÂ`&°Øá™4ÿ휃‚>'-¯]âSü7¾'Œ¸ŒÙŸwNñÝžï#ÿ÷É$çûëa`_ïìÄ#°ä4»˜ä;6ìz Ç›Ð¸B›±ŸÜˆÆE{oÃõEùoÓ[uŽOÅÛ Æt’¹[&>üY”ÀÑ’²3)øWàCh5"EY D—Ö“-iz¸÷Ì3ôw¿ÖTÔþá=n™°no‹DS¬ jOù³ÌU)ÅH>Þ à^Âó#8¿êÓ[†¿’î&¹Õd ecÂÁ¬@ é<ü q,?Ó@´c}¨ÏN n¯N`]Ъºz^,¯:fŽ¡¡eë=“”êö“–è2÷‰‚jœöÕJA3 Jjž'n¦&‘‰ÃL‘‚08‘“ïw¨ñfb {]d è@[˜#{ùo9kêÝà‚^†@gg[­×ADž^Ÿ¡‰ˆâMJß”#$AöŸ†ÁlB¹à¼fЗ8»ñèù„¢¶(”DîTuÃ$4CoðhDë¨Ò줃9)Mæ¼A`ØóÞƒ7Õ—Bþ±ŒæÚlzž Š·8Um8! }7$ u~,«|N¸šÿí¡T5Nh¶1{JTuUƒ±†Æ‘à,ô<xRFR›7y 6 ¼\ëÕÆ¦óÄ;JùÃÌ#{í›b>Ñ#@ $ñzq“êæŒ†¦™#²œFf¶kCË+’¤ Žp+°{õþÛÃ\¦RtÎ&wœ-YVìd:ýçÏ>écOÖñ¨Ý×áz@Êhh’×øÍç6ÉGt~¦S‘QOùÄ“br·Ó"¸>xúÒðÃç™Ñ䟧¶~V{Iä9•æ®r‚Žì¡ž@Ka˜ ª[lëèiÞ…õ¡P䂜w V ΧÁ…ˆOd!z7‰‡!û!Cû¨•’Õ)öNÕGNÄ P½ Á5AW©Ðþ”¸ã=í6šf#FQùFÖd4Á”G—eyÍôÔS7Exг&…¶ ”÷’ÞeåSý^aD1­V}Œ(´ê·ÃÉÆrRf[qR/\Xñ¨[0’ñš1±ÞË3ÙˆDƒÒ‹£9…夼g2K…nÉiäÄiää׿‰èS-"A v•‡‰uå Ål¨ÜP.•+DÅi%g,2äi_@*&Óö,Ú„ò>Ÿ]É{ÊÑÀ®Žo%­ê"穬Œ£)Ú´fp®ÕN;Rú^½_Aø³ö‰ÉúV ·‰Æ)i‹š°vœ½åJï8)iß ÷ˆdrfŒ´±0C áųj5 ù"Øn«íîÞv nÝ…å¸2ÍNQpÛ«:ï6…=J8!†<=³%®'ˆ½@P§"µ-p¸•#ãÌf?KUf9wÚç'cÏ–‹Î†Å¼ÈlN ùÏ¥ýò*E| ÌLŒÚqü_˜Äò¾ßL‚³ôØkæ$ᣩÜÖø>Ø4b NÒsEÒop¼ûPô†žÂàv¯§¢.‰V=´Ùzc¾øX þæ…ÑóMÑ>¹‡ì¨Ù‘’ƒ¼ç¡‚ÎjŒ!©“> «h%çþI•ù<¯×$âô¬™TvB0ºydö¡, JÑW‡¾ÿýï€~òÂ$êë_$A8ý9u/¢¤<=—¥€K¶„{×8òr">A̦"¦˳¨ÖA&J5^‰*ƉíMêm=ØÜv÷*Gœ”ú8`¸º6•« ›Ê^uQ.!÷fk}Ó—Ìk,ïÄ>¬]¹)bs.5 ¡• ‘ê(8:kº=eߺ0C™¼^Ø?V&ª‡]›ÏSúɇ?ÙÓ#t½ìî9÷ö\½­w3«Í5¾ÙÇæŽËg<×2òà óJ0îšMNìÏdÙ‰óYñÎ óbσcìY_3Þ? 5c:0yå¨}ôF륞Geûaæ@4Âd€õƒ4WÅiX_ÐÕsÝß7:ÖõEÈŽ*A^cÊX+e‡Ê¸mám‘f |M‡ÊÚm·õÛZ!ÌßThLpÁe¿ØAÀ÷_ŸÑÕÞ¾H‡©Úöœ?ºÍ8n weëæÊÊ-­~òsdûŒ5n¦íøÆ5µWɉH7¸öj×™íiª"‡váÖÐ|w R˜8¬•Çùʧiɶ Gqn±Žª#GùÉš}ÑÍ£«5בái sZ8 ËÓîo‡õ[k=ËlùbØ!˧‘‚΂¤»¶µ¶ÒzÿW«¿øûê‹­5øo½úb¥_¬­À?6W¿©¯®µ¶åœQŠ/Ð÷â`¯öâÿrð_hàÿÖ×Zíݽ–Àdµ¼·ùܤŸQüwùTC_晹:¶Fù’Ž<¨¹ƒ­˜X&TÜ ËŸ9öÈ¢³éŠû ˆÊ¦MfÓ¦Ó#¶‹nÚ{è©Ë{8êÓúæ¥V3µ»2;´Š®—7¹Æ[!öCm£JÙ?¤~óƒ«rW Ý0ì%Å$4t-K>pÌ"óAh§€GL ¢Ä,ÛbJ‘ŒÊ94Š—©^V*žóŠÔ-œ !÷ 8·©ÙE‹+éØåë-$b*l(ÉZ·ÅZ…<Ó8M‹g¸«ñ [ü…<“)bòL#Ã3ù1ÙàÈ)<“×ÔòLƒx†#æä!Ž®Ó É>ø±¥­ Ú ûžCÁ}ö¯±Æ¨¯ 1A¶¬S|F„S³¬—J5n„·™¶r<Óº¿ŠÙ™´–´ý”Û½º$­Y槺9-Èè™ -nY}Çs˪M‰&¥ÍœkµZGíCŒæjϨAŽÔÝŠ“Ëx4IPŒTl+˜Í‹ámU àÿŠ…‡Q¼ª÷LsytÒ=>éîï´‚Å)cŽeÚïòe+yêerôj^ ^ób#Ô$ãºÖtn@iÖ%ïðóç;ÏC~ñìÌÑîìâ¸ëÉ5uC#U,žiàÎ^rv@Nây6>3kgïÁ¶½Ç”ÃÖP˜ Þ- ·¸SÖ':´fý¬ZÏ{CEÅó£—Ë¿B²¨ÃŠrfß:h¢VÑÃ~§Ø‘)n$¥ž6ÏGêúáŸ0<”_Ú`ŽLdz¼ßÉœ§å|‡»¨|¥ûlÔˆáÄýa¦–¾õù‘AÛ{û ½ÀƒÅÆ{fXýœ8æÝLd¼yƒø ©¥üKmµ’#ÄÏf ±«á+÷ïQePçjÛPý¬¾7žf9êÀ÷nܯ²(pÅŠÆi™c¾Ë5]¾g¨“eðàäe}P’uD,K§»wü´ d C糑UHØU´¦$‰Æƒ¹÷.zð¬p%}ìz7çÖ=lüúôs/ ¸óç]sÎð¢J̼ª9ÿ¬_"Î7˜¾i„Ì9ù„š1›à,TcŸúÕ‡ç±Å=´÷´X-òÆÎÑÛf£õ´¼¨Ò…å2£.¡Ô‰ˆ¤­ég7ïåË„žŽc5ã?u,mk»¨ý2šr¼_ ¬º £·>Ô †®ËûµorÂê“PàKë¡ôÎ0Ž.Äœ¶ÂÌBìxÚ4ây7­à6>ª~ïlC20µi/ãËœ(ç=Sf·Ÿ•…Î FÀÿßkÛ5$F’É0GòR¸‹ÕÚ•Qí³íåãF·»×~ê½|ÜÃÌÏE{Y•Xâ÷‘%K9}î».¢¯Å¯ËÏ{;Ý£vóövŸveØ‹ºt¿6f™i«£Ë>ÆúèÞ¿B‡ ОÚK NRü«Ö|üØ¡¶}/µÇð%êÌ:oÎÊRã½½:߇_TÎyŽÂõ×CSŽˆ!=ëí4Éi¥Œ†lp\½¡Ôµ~þ”}Ö˜³Jm¨ò¾•Ò„ºôƒhAÊf²ø}ŒN‘½ÝVN.ºÆpóÙ­zøŽlÌCçÚt'‚?{žÂWu\E½8A¦t2ß!ÅmT.²t”›ÎÀ{,ôÏŸ…­sx=ÕØ1ŠLÓ§ªèc¨SÕÙÃhÓN³õA0=¹VíÀÖ¼‚­P¬]u©©«d”~”…2ú[üZIWàÁÑñl.õóãq8ÝÈ¥¦­•Yú1ÖÊìï!öÕ¯Gíݽ'ßS·GÉ ,ÜO²Äô½Ä%gq_‹_—·»ûO»$@@þjÐÓ =ÆàL•Ÿ~'Vן3¢¶:7Ì” ”E<þü ²›Siœ 1{Ãü¹³™oþ€ÙYî™7{ óظҥ—|Ê‚™ªÊ0ÿQv2æª^T„Æ‚°dKXÁù¿U)»™\È΂ùgSøp©Æ¦\C”mòŒ)†É9¿äuÂ%åÖkž+Üô!^.‚:Õ¹0 ø†R„ãÔ­O73¯ ës2Ü£~Â[ Wá$:Mmº¤£ÔWiø¿Wtvvjo‰iRµeê‹à wy:èQà)Ù 9ª_@üV}ùAÝR©In#¸Ç#• ;ÛŠ&ã•;+7¿T„·Á¦›÷S7ñºÜ<ÀLNÂó;·ößÝÚ?S¹ô&Öœìpºæ·SjÖ­š\uÿ¨Ým7ZAçämû褋±GŒÑ»¡ ñ×Êû A.¾«Ð› 'DEDI$EOdØDEW€§å !&2V"£$ÂBPDBF$¬C†BdÜCHùl)sms·¹»*AturÙµì¬Sb9{ëÆÐ¹2as5•~l· ¡\:Ð^먵Þ8鵎N„ï¼ËòÀg^XD”yÐ#üG>šc7KKñ~>½«ˆÇ~ÿL¢UV»» ‹ÐL? •Ï`¥]EŠ`Ây&`+Ÿ)ÈJ»ŠÎh,žsLüC Vòäwò' ~ÆÉ†Ÿ pÊù_&ê'Ó «¼²'š`ÎÉ• 2—Ý(‘›òN[¡„ÕÐïÁf_ßzãѸ]ËŸ`¦P©ôŒ´ËùTâÇm£Éͼ&ì?Ix)ˆT˜W8x\õõQË ¬tVRØaÝ×á4y¯fZë_H…˜ÓCÍ×C“Þ¦ŠDÀ˜ª.‚–G“¢†ªoäwü,~jŽæVÞP©šUj‡îÿÝÄ~z›5ë³Ô¬¨ô€pæCþ–M‰‡åo4ùó8†ýÂñQ§K–y ó„…ÄDf#þ “R²Ï-+è –ÜôL†=Â(i? õ”ìwj›hâYˆ¸èTEL¥a)ßFƒLƒ3 ·ö¢huoe_Hß`A!0DžAl=Ê þ…¦]¹A(+Æ]n/ebg•…ê¨Ü(^=Ê(z0ˆñ¤Ô ¸èlƒxý(ƒHÂ…ýrƒà¢³ âï2„>)5Šƒ“€ 㔡ÝßLÅ·3Šh-—“OqróÍi¯ÿq´Ôi:Ùp!î”øI<¢ª‰[xCY¼ë=‘FÙ¿"…Ī#«kLÐxèÙpv0'•ŒÊŽ"gÔ8Ð×3zêmc0ZÑ L‹J×gvP)1¾²”4Š ½½Ë«ò,UN$¯ó»:¿›­s: =÷)$HûšKReW(Kš?m¢ZÊ©ÆC)óAX~:?ZW¹vù2´M“Íe= 7Úó+ÂK¤ZRFiîüæUÈ@aYšÎp,úB]JÈUpíÒs˜?7ÈeÚŠ‚bê®zxòÙB+O¾S>C¾iò=<ùã^‚‡²òôg*d`š{?©GK S!3K5?ÂX‡–€S>K¿¡”|C`ó³°©È­QV÷)ã“_ªÝŒäÝúÈç›Å’¼wŠ©ÖD®þ<±î%ÇkЦCÞdFáL3iÏ»î´@pÅk«3Ͻ‰t˜cöÌFùí\”ׂò»Ù(¿›‹òÍ9)g~<¯s£ ¹n:5rìäºk'§ÊP.4q±€¶ñ7ã;Åè··sé}Y‚Þ—O@ïÂäÉŒ²€K…ïü%Œâ«i@ïYÍ|#¤Äíd£?µÒŒUø{µµEÿ}ýê¥õßju³¾õjó«ZõõÖËW¯^mm¾þªZ{ùªºõUP]4!¾¿+" ‚¯ºñe/Í/7íwLUý÷?äj'ß%ÑùÈÒUÂ¥¬<Ú ›„Qÿb|7á?^¥a’n¤ñUÒÇœòçáÆ(œü°t4?žëÁq¯ÿ±wÎ!@².N`0$wyM”|—Aá—–º!=Nâó¤wIOQº¥ñÙ䦗„ÛÁ]|ô{Z0ˆ@ˆE§ø~?šÈ˜ØÑÙÝ|q5„…[ü2•¡T?µN‚ŸÂQ˜Ç Y£~põ): †;Æo0ö#8½[Ââ$[;¢w'¢·ƒ0"¨ƒk˜ܾuÙh­£^Z¥ËùU òN€:‰zÙëqaN,jóß?Ð3P˜eJCŒ4XÂל¿4»ïŽNºA£õ>ø¥Ñn7ZÝ÷Û*G=j2Ž#©A³7¨€FD Z:Ük#ò·Íƒf÷=&ùÞov[{Fjàíðz|t|Ò>>êìmA‡!Ø— ¦óŒ–#Ádú“^4La¨ïañR Îÿôš6 ûa„Éå{ ñÆwÓ×h©7Œ¡ˆa&Ƽmó×I%¸I"‚æ 2«·¤WL¥Q£¼¬A‘Þèãæ,Ó¨îGgÐøþ0Ž“Jð6-ÅAµ^«U×k›ÕZpÒi,XXï?ïý¾sÔÚoþôû;ÐÿúèÅ –ûñè,:߸XŒè1œ—ÿP«ÉFYNuÕåGØ(QéRÑâw ­7.~`#ÆiõüPÓ|SIm¨º)ÙR¢º]— NÌjÂì™uQ,{ÎÖ•&Ÿ·ò²Ö,0ÙÊü3ëâ³^?L}µià¾Ú8dhš&lõP}eʬ#´o- Ã’"K{#¥ÿU˜"Öûñzö#~aŸhcw760Ë\~Ô» ¹<~’l¬Byçb| >á*”©—ëØ`‡TƤË7ÏUØL5Xá.)‡Ú#dlŠ6Õ—«ØÞˆ¶ ͆‚YO•!þá`#8B9v±§H÷RS½(ld’7D“ 5Ži‚q¾¢ QA%Víº¿dÅ&v%ÍBŦ¨NG6’3aª‰„$ác²$ùØHÑ ¨E< {ªyƒÊÖx¤L3z]ݰ×lS.†5nl!!^#+(ˆ'qd¨JÓ»ýÎrÌ6f1$ NP¦ÇFp¶H"¡¥ŠŠ¬UÍîcØqr"ÒO‚±…wÈK€ð³b±EÈ–cÔ Áå¤ u*P±—½a‡®vz5ÃNæÅD¬kèù|Ÿö†¼2B6øÎºÑÊÖðv«ÇÉDviâ¾ Ž”N­F.èÉàk|õ ]픯é±96òæ4އÖY±u¯@"H‰Ošn‰ºKè¸k43ê¨ -]‹Í§nâì#P†ˆ£ N®½‘¾-K].OU¾|¼Úu©ÑtcBA² L]³JTYA«Ei<ÞHu„£Ëú:Ýì"÷RÇb^ª‹º< œ^'®S“Tc’:ád‚<Ù{®&ë¢Oч®}˜sã²fÎs×—[Å{g”¦ëƒËSïeÑÎïð>™Û•Dwè Ä¡Þâ`Ø¥ÑÀ¸ÿÊL\ýÄ4*?qsL‰—U¯pzfZÿÍ7©œÇáÄ©’Py,ÆwŸ±\Þ2 º—uf¤{Ë¡%ÊÍE< =”¶ Z_± ¸žqÒ(RÊQà#Ú¾}#š¤c/]+üfåôêüI_%xi³jWƒjÌÚ2œfÆË%HÖ.#Hš¹/dt>î#çÐ l@ô“2v÷»¡aòàÐðI›†Ê¤,ÞšݾNK£`á&f>ãÆÑp B‡Ö÷Êeï·4å•’\N,˜8¢Eòö&ïXÎGË7övâÌ*8“o«'ḇîà×/蔄®=%·2ÒF^šÑiדòíã-¹¸¤†>9½ì•e¼á]–þÙŸáL‡Òå"ŽƒIx :á|ƒzÁ›½Xœ˜ÓV+bÊÄ… É«þäJøxöpbÖ|ö ÜÈØô8X^+»²*§åKì–OP„ÎôÀpF7‚·Y¹mqƒ#ú {!ø± §CiÜrºKŒÏz¢ Æ¨óBÍ3'ÔãUB ©B²3ÊqÜKá|î?*³¸GI˜¹.º;ç)°´î*ÏÝÇ›B9²î/Äz›ßè£iÁõ…¡ ø‹p¨ÔÝ”`|ßo¯(øxy™ä¿ìÁÑ ©Ÿ(âÝ÷Cbü°$=ä† %×\"âvõ4NžéªÍ<ÿÑ càðˆ¦iA²žaëÀ+e¡úU …'E•V6Ἃݛ†¸ÕÂ’¼\aK)áø}iÊKv\z»yÁ¨âîÌàm­6[kôP@°’·½zéö2šŸØqU5ó=;|¶¥jÓß{ñ=´lnl”¦¦§N+r˘vCIÑw56º“O1ü:êftìÏ•l8/-EEh¥U‘fþßÿ$—¨È‘Ê6Ö'¢©èKzGðEE£ÎÛ=jñ›3–>ïæ ¦²B“—ެ¤ÝgTšÍtò÷‰mvÏ Y»Ì?˜:nÚÈA‘¡üùŒG^ô@œŸÑÞv.˜ÄζÏ'V"┕٠¦ÓæFI¬Ää7fá$[8q çŸøÍH|yj‡œ?­u*ÿ]E—04Õ=Ë‚ìW{Ðÿ9æ+ÑýŸo½:o9þ¼æ«xÿ2«ýêwz˜<ÜüïÔþï©ä{·h}ÍÖë[øilá­ÅØÂλ Ÿ~™&3¾-g1ûú4Ìå\ãÛc,ç6UŸfyo–k¬ÐìÞÌ1»7g1»·|fw™ey\›{kV›;o6ÝŽþÆ1"Þ6[Asç]°Ûn¶Z­ÿ¾Æ„˜2…Tnë[Y¯ñÔ«é"£{Ë2==òsN»Ó×ÒbÌmÿDýrÔhíîµ;‹&e¡†Óäß›j[°ÃXn2×éÛþI~të|Áoêþ“þ<ïÿ.ÝGñû¿jýeÍóþ¯þåýßcü}yÿ÷åýß—÷ó¾ÿ™aÖ{¿vÿ}I¼í³¿ jKKøJ û\$¸ïƒ‘m»e܈-Ïßè4¥ƒܦ ö}C¥Û£9®¼-ê,/ãÎÑd°×‹ßþìGÿã;ËG~ÿ_߬ÎwôÿË×›_ôÿcü}Ñÿ_ôÿý?§þ_À³üùß·Ã/ûÑ­8“¯3¦ žE·øLÝóçâ&Îëâ~ˆ]ÎM>Òöîèm:VØå‹Ë®BH†äÍ ë0Ä7¸q–÷›¿î½ 666–q/òlô¨aጧà.‹è˼A§9.L§Šh÷딓•³ãá“9'éyv®pì=Ô©=x?‘ H~K{ö{âÕ Þp‘4¤ Y‚Zg¶ôðJÌ– Àž­ äù²=… s`Mø:ï&V¹xú⑸†äˆaiHÙ‰ š˜ãˆøJaAÝ Šg£+îG<™ÂìØg4ÃÞH?¼—™„0¦«§1>!’¢è¦U¤›ªD\(Ñ㨳, XZ)*ÿT7]«›5ož ¤Q^;ã]6¾ct¿:rÃ¥æ»Ñy€{”zÞõ‰y¹áyþ #Ö…j9…p¶%Až´.}ŸËB»a>l…Çjò¹vvŠr¶ÇSyÿg‹*È8'3È¢ìëg¾›‡ívö?òštÙ›¨Àþ0A²Œ{|ÍÆŽ˜²¨I~I©ûQk•Åò’ûÞœ/†™a}èIDŽ‹¹W1Ðø‹ô]ã"ê¡ø‰@)‚gÏÄí¡üöDªPwA jµ¼µ­Zò¾Æ‰'¶_Óà2‹¸C…¾¥dðÂG[QîŽd"“»°a÷__k¦¯²,˜Y岫5ÿZµãßB% ·k• ¯2K¤IºÿúèQßwqJlÀ…/ƒä=øÂ`m£U–D¹Ëÿßi¤Ä›º.-&-w×d#(ÜùfͳŽ?ø×‘0T2…™×{ Á’ÂbÊEA‹ùš¡zÆϹ÷܇S™¡ º…3®ùªLåYré`"ükÛå=×+«–Й…km+ŽŽ¦½Gÿ¿d6bƒìpÞúÔ'šÿíÛ>Ê¢”œÙ > %cJóË8Û-ÛSñ&hIÓ7Óy„N D¤ª)7%ä éË«Vg–x]äš rYAaUYÂxQe=©2~Ù”¿Ú?á\ª¸%õ“Ú£~uøÍ™ÿmš±}D<µžGQT^\ãèI«3íBâllymJ¶¾stxŒp±¡Ì}ÂÆ¦©r#Žœ…õÚª‹cS»‹Ú$hâ𶆃T.á@/›£“1 9a4@µ/ ž Q¼¾Rò^ð»q ðƒ L ÊiyÜ„ì]*œDçm]d­vfº"5]òç…â“ ¥P° ¾óLfCe_F¦…·c‚àû©àX¢šf³Î‘ßÂt|.z~2).¦ã‹ ÿ"ÈÝ'»ÐKö뢹Ñz9A.Œ=ÓøõY0õä)$€: *„¡5ù¡.?l~ð”ß’¿¾”^ɯ}åÿ.ýVu¤»¬9€J3ÁÚ•ÒL¼g©œ`1 å:þ‚d~ÖÊi¾AÌ®œäô/T?¹ÐAëúfÞ³ât-$è•ÇHñXcÖáäö¯«óÞ5I2jxg‹ÒB¼$ÏQѯrøù¬cj?(€-ä~3š´3ßìøô¥WòôP¡¾ù›GÜóÆAãá‹E#~ŠŽÞâ,vˆÃzM»(^MäÌ”[W‚ÎñE=\6Ñ s«žx§f}JMûŽÅ©¬S.G~`TË—9ÐJxA·9F#½”úô׉‰ü+ýyâ?ûýÇf­^Ëľzý%þó1þ¾Ä~‰ÿüÿ¹÷‡{¿zÞзøþvØXwãë syÓ‰þNëö·ä¶Ú¶ºÀ;XÕ2Ý-× t(.ÃQm²ß_WU)ñŠ¢Læ¶[¸(Ñ~Ÿ1OÄÛöR¦‰¢¸…l‡ÓQ²u¦Gxh*º³×Åç¿Þ.j¢ô-„¯•)^$Ä‹ø«¿‚ùëþ™öhöË‡è£Øþ«U_¾~åØ[¯·j_ì¿Çøûú¿‚Œý÷j}.#šRv`#{,Á"µþ_ÿ¶µKÚYˆ1íÜß„Fʘ„þáÏjB÷4 ¡…ûY‡ÐÀL"üþV"4rCª/ÔVÄ××Ö1/Y4:‹ñ3~õ#Xjhø‚àåöÚaü)øã·¯{ÉŸ>ß H2#^ |óãgW£O”ˆ<ù#ÆùÁg®ÌõéƒüǸ—Ôd)ø\Çσx’Bë«6·Á;œˆLQ;÷é‰Píß©ÆoCõú…Ÿ><­jsjW+âµ¢,âíljÒ@ä‘Ë8¤)¼3\O' ÿ¦‡WŒ²`Œ¥œ¶ ¿äï¬j½áyxšô€ù¸ìnêoøÈ%¿îMÒ9¯ÿøí" Dò{zéFÿ‹\¼ëEI˜$³Ü±„îÖ²,KF8*żzŠcMÄ´ê,§,D$³ü'®—œºö¬Ámï;ÓŒä"»CüŠŸáe̶ÿ‚÷¥úWú·²RDû?¦aˆ—÷Bq~ZZR‹ôg+ïÕ„I"3®Š€°S8v=÷ëÝç«Áß¾6ùš¯nWž†·×xÙ_qY^)Gø9åùªL¸Hiâþ¨½ñ§O‚NO{šð?Þ|’áøÂ™þÿ¥¯ÿ†SÿÿÁ™à{‘ƈm‡Ãn<|^ jáz­C°®ÔŽ™Å÷w+ßßÖW³I˜54ópL=—íØ”†™7Öh’Ä”Í2NîVY¿)fåå½é¥Üˆ)”5 åVC¿Ð? A„!C‰DÒr#‹v„²Ì\·,ä .“óƒíŠg‚½/;ܱL½pChÚ6…ÐÕS,ö :áy¤ð=ûIE¶ñò—>µ÷Çöÿ¥·Oåÿsóÿm½†â_üð÷Åÿ÷Åÿ÷Åÿ÷¹ûÿÒÛÏÀÿ÷dDÌáÿ{@ZÿRþ¿4¼b”æœ@Qý‹ð‹ð‹ð‹ð‹ð‹ð?Á˜Þ>ˆ’Ò@V󏹿}€Ü`Ö ¸hçm_œVç,ïçßgåüûÊðÿµÃÞà2ܘÜNÞÇ”÷µWÕ þÇæë/þ¿Gùû¯ OB‰‰=: £†üN )Ô;Ú"ñ)èØM´Ïð Ð0KÿÒqÄi‹ÁTgcÎqWlnðqqŠÂLÑôaoÉ j"Rx˜Rj¤: rœN„•†ª: €Ãé3P3bûî¼x±{°«Ý:±B*¼DPùq½Dƒñß_n}ñ6X§FzäLCV¦Á`_=¯Ú“!“ú¦Ñe4ì%ÔB–F%8ÃÁF°ô_Tê]|’a.f¬ÕD Nµв×uHÓ¢Fð($²ÿOžÒÐù·Ö:êî­±,¨NåÂéÕØ˜8±v° 1=PÆ#4“Åô Ìž_ö>†8=ÏuiMa#C8ym 3 èc"¾«±Y¾z¾_1=kø”[—‡r‘ž$à¥Ñ7±¾šë¦ã2ØÌ |€é„ùŒ©¿¾Ò(龜ÒÖÐØ¨fRt|öáKì¡rΜiØKúëøÛ­-ºÐ7jµúßaÉŠ矇øò÷åïËß—¿/_þ¾ü}ùûò÷åïËß—¿/_þ¾üýyÿþoû¡˜(odepkg/src/odepkg_auxiliary_functions.cc0000644000176000010400000004642111711232766021751 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ #include "config.h" #include "oct.h" #include "oct-map.h" #include "parse.h" #include "odepkg_auxiliary_functions.h" /* -*- texinfo -*- * @subsection Source file @file{odepkg_auxiliary_functions.cc} * * @deftypefn {Function} octave_value odepkg_auxiliary_getmapvalue (std::string vnam, Octave_map vmap) * * Return the @code{octave_value} from the field that is identified by the string @var{vnam} of the @code{Octave_map} that is given by @var{vmap}. The input arguments of this function are * * @itemize @minus * @item @var{vnam}: The name of the field whose value is returned * @item @var{vmap}: The map that is checked for the presence of the field * @end itemize * @end deftypefn */ octave_value odepkg_auxiliary_getmapvalue (std::string vnam, Octave_map vmap) { Octave_map::const_iterator viter; viter = vmap.seek (vnam); return (vmap.contents(viter)(0)); } /* -*- texinfo -*- * @deftypefn {Function} octave_idx_type odepkg_auxiliary_isvector (octave_value vval) * * Return the constant @code{true} if the value of the input argument @var{vval} is a valid numerical vector of @code{length > 1} or return the constant @code{false} otherwise. The input argument of this function is * * @itemize @minus * @item @var{vval}: The @code{octave_value} that is checked for being a valid numerical vector * @end itemize * @end deftypefn */ octave_idx_type odepkg_auxiliary_isvector (octave_value vval) { if (vval.is_numeric_type () && vval.ndims () == 2 && // ported from the is_vector.m file (vval.rows () == 1 || vval.columns () == 1)) return (true); else return (false); } /* -*- texinfo -*- * @deftypefn {Function} octave_value_list odepkg_auxiliary_evaleventfun (octave_value veve, octave_value vt, octave_value vy, octave_value_list vextarg, octave_idx_type vdeci) * * Return the values that come from the evaluation of the @code{Events} user function. The return arguments depend on the call to this function, ie. if @var{vdeci} is @code{0} then initilaization of the @code{Events} function is performed. If @var{vdeci} is @code{1} then a normal evaluation of the @code{Events} function is performed and the information from the @code{Events} evaluation is returned (cf. @file{odepkg_event_handle.m} for further details). If @var{vdeci} is @code{2} then cleanup of the @code{Events} function is performed and nothing is returned. The input arguments of this function are * @itemize @minus * @item @var{veve}: The @code{Events} function that is evaluated * @item @var{vt}: The time stamp at which the events function is called * @item @var{vy}: The solutions of the set of ODEs at time @var{vt} * @item @var{vextarg}: Extra arguments that are feed through to the @code{Events} function * @item @var{vdeci}: A decision flag that describes what evaluation should be done * @end itemize * @end deftypefn */ octave_value_list odepkg_auxiliary_evaleventfun (octave_value veve, octave_value vt, octave_value vy, octave_value_list vextarg, octave_idx_type vdeci) { // Set up the input arguments before the 'odepkg_event_handle' // function can be called from the file odepkg_event_handle.m octave_value_list varin; varin(0) = veve; varin(1) = vt; varin(2) = vy; // vy.print_with_name (octave_stdout, "vy", true); for (octave_idx_type vcnt = 0; vcnt < vextarg.length (); vcnt++) varin(vcnt+4) = vextarg(vcnt); octave_value_list varout; switch (vdeci) { case 0: varin(3) = "init"; feval ("odepkg_event_handle", varin, 0); break; case 1: varin(3) = ""; varout = feval ("odepkg_event_handle", varin, 1); break; case 2: varin(3) = "done"; feval ("odepkg_event_handle", varin, 0); break; default: break; } // varout(0).print_with_name (octave_stdout, "varout{0}", true); // varout(1).print_with_name (octave_stdout, "varout{1}", true); // varout(2).print_with_name (octave_stdout, "varout{2}", true); // varout(3).print_with_name (octave_stdout, "varout{3}", true); return (varout); } /* -*- texinfo -*- * @deftypefn {Function} octave_idx_type odepkg_auxiliary_evalplotfun (octave_value vplt, octave_value vsel, octave_value vt, octave_value vy, octave_value_list vextarg, octave_idx_type vdeci) * * Return a constant that comes from the evaluation of the @code{OutputFcn} function. The return argument depends on the call to this function, ie. if @var{vdeci} is @code{0} then initilaization of the @code{OutputFcn} function is performed and nothing is returned. If @var{vdeci} is @code{1} then a normal evaluation of the @code{OutputFcn} function is performed and either the constant @code{true} is returned if solving should be stopped or @code{false} is returned if solving should be continued (cf. @file{odeplot.m} for further details). If @var{vdeci} is @code{2} then cleanup of the @code{OutputFcn} function is performed and nothing is returned. The input arguments of this function are * @itemize @minus * @item @var{vplt}: The @code{OutputFcn} function that is evaluated * @item @var{vsel}: The output selection vector for which values should be treated * @item @var{vt}: The time stamp at which the events function is called * @item @var{vy}: The solutions of the set of ODEs at time @var{vt} * @item @var{vextarg}: Extra arguments that are feed through to the @code{OutputFcn} function * @item @var{vdeci}: A decision flag that describes what evaluation should be done * @end itemize * @end deftypefn */ octave_idx_type odepkg_auxiliary_evalplotfun (octave_value vplt, octave_value vsel, octave_value vt, octave_value vy, octave_value_list vextarg, octave_idx_type vdeci) { ColumnVector vresult (vy.vector_value ()); ColumnVector vreduced (vy.length ()); // Check if the user has set the option "OutputSel" then create a // reduced vector that stores the desired values. if (vsel.is_empty ()) { for (octave_idx_type vcnt = 0; vcnt < vresult.length (); vcnt++) vreduced(vcnt) = vresult(vcnt); } else { vreduced.resize (vsel.length ()); ColumnVector vselect (vsel.vector_value ()); for (octave_idx_type vcnt = 0; vcnt < vsel.length (); vcnt++) vreduced(vcnt) = vresult(static_cast (vselect(vcnt)-1)); } // Here we are setting up the list of input arguments before // evaluating the output function octave_value_list varin; varin(0) = vt; varin(1) = octave_value (vreduced); if (vdeci == 0) varin(2) = "init"; else if (vdeci == 1) varin(2) = ""; else if (vdeci == 2) varin(2) = "done"; for (octave_idx_type vcnt = 0; vcnt < vextarg.length (); vcnt++) varin(vcnt+3) = vextarg(vcnt); // Evaluate the output function and return the value of the output // function to the caller function if ((vdeci == 0) || (vdeci == 2)) { if (vplt.is_function_handle () || vplt.is_inline_function ()) feval (vplt.function_value (), varin, 0); else if (vplt.is_string ()) // String may be used from the caller feval (vplt.string_value (), varin, 0); return (true); } else if (vdeci == 1) { octave_value_list vout; if (vplt.is_function_handle () || vplt.is_inline_function ()) vout = feval (vplt.function_value (), varin, 1); else if (vplt.is_string ()) // String may be used if set automatically vout = feval (vplt.string_value (), varin, 1); return (vout(0).bool_value ()); } return (true); } /* -*- texinfo -*- * @deftypefn {Function} octave_value_list odepkg_auxiliary_evaljacide (octave_value vjac, octave_value vt, octave_value vy, octave_value vdy, octave_value_list vextarg) * * Return two matrices that come from the evaluation of the @code{Jacobian} function. The input arguments of this function are * @itemize @minus * @item @var{vjac}: The @code{Jacobian} function that is evaluated * @item @var{vt}: The time stamp at which the events function is called * @item @var{vy}: The solutions of the set of IDEs at time @var{vt} * @item @var{vdy}: The derivatives of the set of IDEs at time @var{vt} * @item @var{vextarg}: Extra arguments that are feed through to the @code{Jacobian} function * @end itemize * * @indent @b{Note:} This function can only be used for IDE problem solvers. * @end deftypefn */ octave_value_list odepkg_auxiliary_evaljacide (octave_value vjac, octave_value vt, octave_value vy, octave_value vdy, octave_value_list vextarg) { octave_value_list varout; // If vjac is a cell array then we expect that two matrices are // returned to the caller function, we can't check for this before if (vjac.is_cell () && (vjac.length () == 2)) { varout(0) = vjac.cell_value ()(0); varout(1) = vjac.cell_value ()(1); if (!varout(0).is_matrix_type () || !varout(1).is_matrix_type ()) { error_with_id ("OdePkg:InvalidArgument", "If Jacobian is a 2x1 cell array then both cells must be matrices"); } } // If vjac is a function_hanlde or an inline_function then evaluate // the function and return the results else if (vjac.is_function_handle () || vjac.is_inline_function ()) { octave_value_list varin; varin(0) = vt; // varin(0).print_with_name (octave_stdout, "vt", true); varin(1) = vy; // varin(1).print_with_name (octave_stdout, "vy", true); varin(2) = vdy; // varin(2).print_with_name (octave_stdout, "vdy", true); // Fill up RHS arguments with extra arguments that are given for (octave_idx_type vcnt = 0; vcnt < vextarg.length (); vcnt++) varin(vcnt+3) = vextarg(vcnt); // Evaluate the Jacobian function and return results varout = feval (vjac.function_value (), varin, 1); } // In principle this is not possible because odepkg_structure_check // should find all occurences that are not valid else { error_with_id ("OdePkg:InvalidArgument", "Jacobian must be a function handle or a cell array with length two"); } return (varout); } /* -*- texinfo -*- * @deftypefn {Function} octave_value odepkg_auxiliary_evaljacode (octave_value vjac, octave_value vt, octave_value vy, octave_value_list vextarg) * * Return a matrix that comes from the evaluation of the @code{Jacobian} function. The input arguments of this function are * @itemize @minus * @item @var{vjac}: The @code{Jacobian} function that is evaluated * @item @var{vt}: The time stamp at which the events function is called * @item @var{vy}: The solutions of the set of ODEs at time @var{vt} * @item @var{vextarg}: Extra arguments that are feed through to the @code{Jacobian} function * @end itemize * * @indent @b{Note:} This function can only be used for ODE and DAE problem solvers. * @end deftypefn */ octave_value odepkg_auxiliary_evaljacode (octave_value vjac, octave_value vt, octave_value vy, octave_value_list vextarg) { octave_value vret; // If vjac is a matrix then return its value to the caller function if (vjac.is_matrix_type ()) { vret = vjac; } // If vjac is a function_hanlde or an inline_function then evaluate // the function and return the results else if (vjac.is_function_handle () || vjac.is_inline_function ()) { octave_value_list varin; octave_value_list varout; varin(0) = vt; varin(1) = vy; // Fill up RHS arguments with extra arguments that are given for (octave_idx_type vcnt = 0; vcnt < vextarg.length (); vcnt++) varin(vcnt+2) = vextarg(vcnt); // Evaluate the Jacobian function and return results varout = feval (vjac.function_value (), varin, 1); vret = varout(0); } // In principle this is not possible because odepkg_structure_check // should find all occurences that are not valid else { error_with_id ("OdePkg:InvalidArgument", "Jacobian must be a function handle or a matrix"); } // vret.print (octave_stdout, true); return (vret); } /* -*- texinfo -*- * @deftypefn {Function} octave_value odepkg_auxiliary_evalmassode (octave_value vmass, octave_value vstate, octave_value vt, octave_value vy, octave_value_list vextarg) * * Return a matrix that comes from the evaluation of the @code{Mass} function. The input arguments of this function are * @itemize @minus * @item @var{vmass}: The @code{Mass} function that is evaluated * @item @var{vstate}: The state variable that either is the string @code{'none'}, @code{'weak'} or @code{'strong'} * @item @var{vt}: The time stamp at which the events function is called * @item @var{vy}: The solutions of the set of ODEs at time @var{vt} * @item @var{vextarg}: Extra arguments that are feed through to the @code{Mass} function * @end itemize * * @indent @b{Note:} This function can only be used for ODE and DAE problem solvers. * @end deftypefn */ octave_value odepkg_auxiliary_evalmassode (octave_value vmass, octave_value vstate, octave_value vt, octave_value vy, octave_value_list vextarg) { octave_value vret; // If vmass is a matrix then return its value to the caller function if (vmass.is_matrix_type ()) return (vmass); // If vmass is a function_hanlde or an inline_function then evaluate // the function and return the results else if (vmass.is_function_handle () || vmass.is_inline_function ()) { octave_value_list varin; octave_value_list varout; if (vstate.is_empty () || !vstate.is_string ()) error_with_id ("OdePkg:InvalidOption", "If \"Mass\" value is a handle then \"MStateDependence\" must be given"); else if (vstate.string_value ().compare ("none") == 0) { varin(0) = vt; for (octave_idx_type vcnt = 0; vcnt < vextarg.length (); vcnt++) varin(vcnt+1) = vextarg(vcnt); } else { // If "MStateDependence" is "weak" or "strong" varin(0) = vt; varin(1) = vy; // Fill up RHS arguments with extra arguments that are given for (octave_idx_type vcnt = 0; vcnt < vextarg.length (); vcnt++) varin(vcnt+2) = vextarg(vcnt); } // Evaluate the Mass function and return results varout = feval (vmass.function_value (), varin, 1); vret = varout(0); } // In principle the execution of the next line is not possible // because odepkg_structure_check should find all occurences that // are not valid else error_with_id ("OdePkg:InvalidArgument", "Mass must be a function handle or a matrix"); return (vret); } /* -*- texinfo -*- * @deftypefn {Function} octave_value odepkg_auxiliary_makestats (octave_value_list vstats, octave_idx_type vprnt) * * Return an @var{octave_value} that contains fields about performance informations of a finished solving process. The input arguments of this function are * @itemize @minus * @item @var{vstats}: The statistics informations list that has to be handled. The values that are treated have to be ordered as follows * @enumerate * @item Number of computed steps * @item Number of rejected steps * @item Number of function evaluations * @item Number of Jacobian evaluations * @item Number of LU decompositions * @item Number of forward backward substitutions * @end enumerate * @item @var{vprnt}: If @code{true} then the statistics information also is displayed on screen * @end itemize * @end deftypefn */ octave_value odepkg_auxiliary_makestats (octave_value_list vstats, octave_idx_type vprnt) { Octave_map vretval; if (vstats.length () < 5) error_with_id ("OdePkg:InvalidArgument", "C++ function odepkg_auxiliary_makestats error"); else { vretval.assign ("nsteps", vstats(0)); vretval.assign ("nfailed", vstats(1)); vretval.assign ("nfevals", vstats(2)); vretval.assign ("npds", vstats(3)); vretval.assign ("ndecomps", vstats(4)); vretval.assign ("nlinsols", vstats(5)); } if (vprnt == true) { octave_stdout << "Number of function calls: " << vstats(0).int_value () << std::endl; octave_stdout << "Number of failed attempts: " << vstats(1).int_value () << std::endl; octave_stdout << "Number of function evals: " << vstats(2).int_value () << std::endl; octave_stdout << "Number of Jacobian evals: " << vstats(3).int_value () << std::endl; octave_stdout << "Number of LU decompositions: " << vstats(4).int_value () << std::endl; octave_stdout << "Number of fwd/backwd subst: " << vstats(5).int_value () << std::endl; } return (octave_value (vretval)); } /* -*- texinfo -*- * @deftypefn {Function} octave_idx_type odepkg_auxiliary_solstore (octave_value &vt, octave_value &vy, octave_idx_type vdeci) * * If @var{vdeci} is @code{0} (@var{vt} is a pointer to the initial time step and @var{vy} is a pointer to the initial values vector) then this function is initialized. Otherwise if @var{vdeci} is @code{1} (@var{vt} is a pointer to another time step and @var{vy} is a pointer to the solution vector) the values of @var{vt} and @var{vy} are added to the internal variable, if @var{vdeci} is @code{2} then the internal vectors are returned. The input arguments of this function are * @itemize @minus * @item @var{vt}: The time stamp at which the events function is called * @item @var{vy}: The solutions of the set of ODEs at time @var{vt} * @item @var{vdeci}: A decision flag that describes what evaluation should be done * @end itemize * @end deftypefn */ octave_idx_type odepkg_auxiliary_solstore (octave_value &vt, octave_value &vy, octave_idx_type vdeci) { // If the option "OutputSel" has been set then prepare a vector with // a reduced number of elements. The indexes of the values are given // in vsel if vdeci == (0 || 1). RowVector vrow; if (vdeci != 2) { vrow.resize (vy.length ()); vrow = RowVector (vy.vector_value ()); } // Now have a look at the vdeci variable and do 0..initialization, // 1..store other elements, 2..return stored elements to the caller // function, 3..delete the last line of the matrices static ColumnVector vtstore(1); static Matrix vystore; switch (vdeci) { case 0: // Keep the resize command here because otherwise we stack the // new values of t even if we have already started a new call to // the solver vtstore.resize(1); vtstore(0) = vt.double_value (); vystore = Matrix (vrow); break; case 1: vtstore = vtstore.stack (vt.column_vector_value ()); vystore = vystore.stack (Matrix (vrow)); break; case 2: vt = octave_value (vtstore); vy = octave_value (vystore); break; case 3: vtstore = vtstore.extract (0, vtstore.length () - 2); vystore = vystore.extract (0, 0, vtstore.rows () - 2, vtstore.cols () - 1); default: // This can be used for displaying all values at any time, // eg. if the code should be debuged or something like this vt = octave_value (vtstore); vy = octave_value (vystore); vt.print_with_name (octave_stdout, "vt"); vy.print_with_name (octave_stdout, "vy"); break; } return (true); } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_auxiliary_functions.h0000644000176000010400000000401511711232766021604 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ #if !defined (odepkg_auxiliary_functions_h) #define odepkg_auxiliary_functions_h 1 octave_value odepkg_auxiliary_getmapvalue (std::string vnam, Octave_map vmap); octave_idx_type odepkg_auxiliary_isvector (octave_value vval); octave_value_list odepkg_auxiliary_evaleventfun (octave_value veve, octave_value vt, octave_value vy, octave_value_list vextarg, octave_idx_type vdeci); octave_idx_type odepkg_auxiliary_evalplotfun (octave_value vplt, octave_value vsel, octave_value vt, octave_value vy, octave_value_list vextarg, octave_idx_type vdeci); octave_value_list odepkg_auxiliary_evaljacide (octave_value vjac, octave_value vt, octave_value vy, octave_value vyd, octave_value_list vextarg); octave_value odepkg_auxiliary_evaljacode (octave_value vjac, octave_value vt, octave_value vy, octave_value_list vextarg); octave_value odepkg_auxiliary_evalmassode (octave_value vmass, octave_value vstate, octave_value vt, octave_value vy, octave_value_list vextarg); octave_value odepkg_auxiliary_makestats (octave_value_list vstats, octave_idx_type vprnt); octave_idx_type odepkg_auxiliary_solstore (octave_value &vt, octave_value &vy, octave_idx_type vdeci); #endif /* odepkg_auxiliary_functions_h */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_octsolver_ddaskr.cc0000644000176000010400000011473011711232766021221 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ /* Compile this file manually and run some tests with the following command bash:$ mkoctfile -v -W -Wall -Wshadow odepkg_octsolver_ddaskr.cc \ odepkg_auxiliary_functions.cc daskr/ddaskr.f daskr/dlinpk.f -o odekdi.oct octave> octave --quiet --eval "autoload ('odekdi', [pwd, '/odekdi.oct']); \ test 'odepkg_octsolver_ddaskr.cc'" If you have installed 'gfortran' or 'g95' on your computer then use the FFLAGS=-fno-automatic option because otherwise the solver function will be broken, eg. bash:$ FFLAGS="-fno-automatic ${FFLAGS}" mkoctfile -v -Wall -W \ -Wshadow odepkg_octsolver_ddaskr.cc odepkg_auxiliary_functions.cc \ cash/ddaskr.f -o odekdi.oct octave> octave --quiet --eval "autoload ('odekdi', [pwd, '/odekdi.oct']); \ test 'odepkg_octsolver_ddaskr.cc'" */ #include #include #include #include #include #include "odepkg_auxiliary_functions.h" typedef octave_idx_type (*odepkg_ddaskr_restype) (const double& T, const double* Y, const double* YPRIME, const double& CJ, double* DELTA, octave_idx_type& IRES, const double* RPAR, const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_ddaskr_jactype) (const double& T, const double* Y, const double* YPRIME, double* PD, const double& CJ, const double* RPAR, const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_ddaskr_psoltype) (const octave_idx_type& NEQ, const double& T, const double* Y, const double* YPRIME, const double* SAVR, const double* WK, const octave_idx_type& CJ, double* WGHT,const double* WP, const octave_idx_type* IWP, double* B, const octave_idx_type& EPLIN, octave_idx_type& IER, const double* RPAR, const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_ddaskr_rttype) (const octave_idx_type& NEQ, const double& T, const double* Y, const double* YP, const octave_idx_type& NRT, const double* RVAL, const double* RPAR, const octave_idx_type* IPAR); // typedef octave_idx_type (*odepkg_ddaskr_krylov_jactype) // (odepkg_ddaskr_restype, octave_idx_type& IRES, const octave_idx_type& NEQ, // const double& T, const double* Y, const double* YPRIME, // double* REWT, const double* SAVR, const double* WK, // const double& H, const double& CJ, const double* WP, // const octave_idx_type* IWP, octave_idx_type& IER, // const double* RPAR, const octave_idx_type* IPAR); // typedef octave_idx_type (*odepkg_ddaskr_krylov_psoltype) // (const octave_idx_type& NEQ, const double& T, const double* Y, // const double* YPRIME, const double* SAVR, const double* WK, // const octave_idx_type& CJ, double* WGHT,const double* WP, // const octave_idx_type* IWP, double* B, const octave_idx_type& EPLIN, // octave_idx_type& IER, const double* RPAR, const octave_idx_type* IPAR); extern "C" { F77_RET_T F77_FUNC (ddaskr, DDASKR) (odepkg_ddaskr_restype, const octave_idx_type& NEQ, const double& T, const double* Y, const double* YPRIME, const double& TOUT, const octave_idx_type* INFO, const double* RTOL, const double* ATOL, const octave_idx_type& IDID, const double* RWORK, const octave_idx_type& LRW, const octave_idx_type* IWORK, const octave_idx_type& LIW, const double* RPAR, const octave_idx_type* IPAR, odepkg_ddaskr_jactype, odepkg_ddaskr_psoltype, odepkg_ddaskr_rttype, const octave_idx_type& NRT, octave_idx_type* JROOT); } static octave_value_list vddaskrextarg; static octave_value vddaskrodefun; static octave_value vddaskrjacfun; static octave_idx_type vddaskrneqn; octave_idx_type odepkg_ddaskr_resfcn (const double& T, const double* Y, const double* YPRIME, GCC_ATTR_UNUSED const double& CJ, double* DELTA, GCC_ATTR_UNUSED octave_idx_type& IRES, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element wise, // otherwise Octave will crash if these variables will be freed ColumnVector A(vddaskrneqn), APRIME(vddaskrneqn); for (octave_idx_type vcnt = 0; vcnt < vddaskrneqn; vcnt++) { A(vcnt) = Y[vcnt]; APRIME(vcnt) = YPRIME[vcnt]; } // Fill the variable for the input arguments before evaluating the // function that keeps the set of implicit differential equations octave_value_list varin; varin(0) = T; varin(1) = A; varin(2) = APRIME; for (octave_idx_type vcnt = 0; vcnt < vddaskrextarg.length (); vcnt++) varin(vcnt+3) = vddaskrextarg(vcnt); octave_value_list vout = feval (vddaskrodefun.function_value (), varin, 1); // Return the results from the function evaluation to the Fortran // solver, again copy them and don't just create a Fortran vector ColumnVector vcol = vout(0).column_vector_value (); for (octave_idx_type vcnt = 0; vcnt < vddaskrneqn; vcnt++) DELTA[vcnt] = vcol(vcnt); return (true); } octave_idx_type odepkg_ddaskr_jacfcn (const double& T, const double* Y, const double* YPRIME, double* PD, const double& CJ, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(vddaskrneqn), APRIME(vddaskrneqn); for (octave_idx_type vcnt = 0; vcnt < vddaskrneqn; vcnt++) { A(vcnt) = Y[vcnt]; APRIME(vcnt) = YPRIME[vcnt]; } // Set the values that are needed as input arguments before calling // the Jacobian function octave_value vt = octave_value (T); octave_value vy = octave_value (A); octave_value vdy = octave_value (APRIME); octave_value_list vout = odepkg_auxiliary_evaljacide (vddaskrjacfun, vt, vy, vdy, vddaskrextarg); // Computes the NxN iteration matrix or partial derivatives for the // Fortran solver of the form PD=DG/DY+1/CON*(DG/DY') octave_value vbdov = vout(0) + CJ * vout(1); Matrix vbd = vbdov.matrix_value (); for (octave_idx_type vrow = 0; vrow < vddaskrneqn; vrow++) for (octave_idx_type vcol = 0; vcol < vddaskrneqn; vcol++) PD[vrow+vcol*vddaskrneqn] = vbd (vrow, vcol); // Don't know what my mistake is but the following code line never // worked for me (ie. the solver crashes Octave if it is used) // PD = vbd.fortran_vec (); return (true); } octave_idx_type odepkg_ddaskr_rtfcn // this is a dummy function (GCC_ATTR_UNUSED const octave_idx_type& NEQ, GCC_ATTR_UNUSED const double& T, GCC_ATTR_UNUSED const double* Y, GCC_ATTR_UNUSED const double* YP, GCC_ATTR_UNUSED const octave_idx_type& NRT, GCC_ATTR_UNUSED const double* RVAL, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { return (true); } octave_idx_type odepkg_ddaskr_psolfcn // this is a dummy function (GCC_ATTR_UNUSED const octave_idx_type& NEQ, GCC_ATTR_UNUSED const double& T, GCC_ATTR_UNUSED const double* Y, GCC_ATTR_UNUSED const double* YPRIME, GCC_ATTR_UNUSED const double* SAVR, GCC_ATTR_UNUSED const double* WK, GCC_ATTR_UNUSED const octave_idx_type& CJ, GCC_ATTR_UNUSED double* WGHT, GCC_ATTR_UNUSED const double* WP, GCC_ATTR_UNUSED const octave_idx_type* IWP, GCC_ATTR_UNUSED double* B, GCC_ATTR_UNUSED const octave_idx_type& EPLIN, GCC_ATTR_UNUSED octave_idx_type& IER, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { return (true); } octave_idx_type odepkg_ddaskr_error (octave_idx_type verr) { switch (verr) { case 0: break; // Everything is fine case -1: break; default: break; } return (true); } // PKG_ADD: autoload ("odekdi", "dldsolver.oct"); DEFUN_DLD (odekdi, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Command} {[@var{}] =} odekdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}])\n\ @deftypefnx {Command} {[@var{sol}] =} odekdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}])\n\ @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odekdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}])\n\ \n\ This function file can be used to solve a set of stiff implicit differential equations (IDEs). This function file is a wrapper file that uses the direct method (not the Krylov method) of Petzold's, Brown's, Hindmarsh's and Ulrich's Fortran solver @file{ddaskr.f}.\n\ \n\ If this function is called with no return argument then plot the solution over time in a figure window while solving the set of IDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{y0} is a double vector that defines the initial values of the states, @var{dy0} is a double vector that defines the initial values of the derivatives, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}.\n\ \n\ If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of IDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}.\n\ \n\ If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector.\n\ \n\ For example,\n\ @example\n\ function res = odepkg_equations_ilorenz (t, y, yd)\n\ res = [10 * (y(2) - y(1)) - yd(1);\n\ y(1) * (28 - y(3)) - yd(2);\n\ y(1) * y(2) - 8/3 * y(3) - yd(3)];\n\ endfunction\n\ \n\ vopt = odeset (\"InitialStep\", 1e-3, \"MaxStep\", 1e-1, \\\n\ \"OutputFcn\", @@odephas3, \"Refine\", 5);\n\ odekdi (@@odepkg_equations_ilorenz, [0, 25], [3 15 1], \\\n\ [120 81 42.333333], vopt);\n\ @end example\n\ @end deftypefn\n\ \n\ @seealso{odepkg}") { octave_idx_type nargin = args.length (); // The number of input arguments octave_value_list vretval; // The cell array of return args Octave_map vodeopt; // The OdePkg options structure // Check number and types of all the input arguments if (nargin < 4) { print_usage (); return (vretval); } // If args(0)==function_handle then set the vddaskrodefun variable // that has been defined "static" before if (!args(0).is_function_handle () && !args(0).is_inline_function ()) { error_with_id ("OdePkg:InvalidArgument", "First input argument must be a valid function handle"); return (vretval); } else // We store the args(0) argument in the static variable vddaskrodefun vddaskrodefun = args(0); // Check if the second input argument is a valid vector describing // the time window of solving, it may be of length 2 or longer if (args(1).is_scalar_type () || !odepkg_auxiliary_isvector (args(1))) { error_with_id ("OdePkg:InvalidArgument", "Second input argument must be a valid vector"); return (vretval); } // Check if the third input argument is a valid vector describing // the initial values of the variables of the IDEs if (!odepkg_auxiliary_isvector (args(2))) { error_with_id ("OdePkg:InvalidArgument", "Third input argument must be a valid vector"); return (vretval); } // Check if the fourth input argument is a valid vector describing // the initial values of the derivatives of the differential equations if (!odepkg_auxiliary_isvector (args(3))) { error_with_id ("OdePkg:InvalidArgument", "Fourth input argument must be a valid vector"); return (vretval); } // Check if the third and the fourth input argument (check for // vector already was successful before) have the same length if (args(2).length () != args(3).length ()) { error_with_id ("OdePkg:InvalidArgument", "Third and fourth input argument must have the same length"); return (vretval); } // Check if there are further input arguments ie. the options // structure and/or arguments that need to be passed to the // OutputFcn, Events and/or Jacobian etc. if (nargin >= 5) { // Fifth input argument != OdePkg option, need a default structure if (!args(4).is_map ()) { octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure for (octave_idx_type vcnt = 4; vcnt < nargin; vcnt++) vddaskrextarg(vcnt-4) = args(vcnt); // Save arguments in vddaskrextarg } // Fifth input argument == OdePkg option, extra input args given too else if (nargin > 5) { octave_value_list varin; varin(0) = args(4); varin(1) = "odekdi"; octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create structure of args(4) for (octave_idx_type vcnt = 5; vcnt < nargin; vcnt++) vddaskrextarg(vcnt-5) = args(vcnt); // Save extra arguments } // Fifth input argument == OdePkg option, no extra input args given else { octave_value_list varin; varin(0) = args(4); varin(1) = "odekdi"; // Check structure octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create a default structure } } // if (nargin >= 5) else { // if nargin == 4, everything else has been checked before octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure } /* Start PREPROCESSING, ie. check which options have been set and * print warnings if there are options that can't be handled by this * solver or have not been implemented yet *******************************************************************/ // Implementation of the option RelTol has been finished, this // option can be set by the user to another value than default value octave_value vreltol = odepkg_auxiliary_getmapvalue ("RelTol", vodeopt); if (vreltol.is_empty ()) { vreltol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"RelTol\" not set, new value 1e-6 is used"); } else if (!vreltol.is_scalar_type ()) { if (vreltol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"RelTol\" must be the same as the number of equations"); return (vretval); } } // Implementation of the option AbsTol has been finished, this // option can be set by the user to another value than default value octave_value vabstol = odepkg_auxiliary_getmapvalue ("AbsTol", vodeopt); if (vabstol.is_empty ()) { vabstol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"AbsTol\" not set, new value 1e-6 is used"); } else if (!vabstol.is_scalar_type ()) { if (vabstol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"AbsTol\" must be the same as the number of equations"); return (vretval); } } // Setting the tolerance type that depends on the types (scalar or // vector) of the options RelTol and AbsTol octave_idx_type vitol; if (vreltol.is_scalar_type () && vabstol.is_scalar_type ()) vitol = 0; else if (vreltol.length () == vabstol.length ()) vitol = 1; else { error_with_id ("OdePkg:InvalidOption", "Options \"RelTol\" and \"AbsTol\" must have same length"); return (vretval); } // The option NormControl will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnorm = odepkg_auxiliary_getmapvalue ("NormControl", vodeopt); if (!vnorm.is_empty ()) if (vnorm.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"NormControl\" will be ignored by this solver"); // The option NonNegative will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnneg = odepkg_auxiliary_getmapvalue ("NonNegative", vodeopt); if (!vnneg.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NonNegative\" will be ignored by this solver"); // Implementation of the option OutputFcn has been finished, this // option can be set by the user to another value than default value octave_value vplot = odepkg_auxiliary_getmapvalue ("OutputFcn", vodeopt); if (vplot.is_empty () && nargout == 0) vplot = "odeplot"; // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value octave_value voutsel = odepkg_auxiliary_getmapvalue ("OutputSel", vodeopt); // The option Refine will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vrefine = odepkg_auxiliary_getmapvalue ("Refine", vodeopt); if (vrefine.int_value () != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"Refine\" will be ignored by this solver"); // Implementation of the option Stats has been finished, this option // can be set by the user to another value than default value octave_value vstats = odepkg_auxiliary_getmapvalue ("Stats", vodeopt); // Implementation of the option InitialStep has been finished, this // option can be set by the user to another value than default value octave_value vinitstep = odepkg_auxiliary_getmapvalue ("InitialStep", vodeopt); if (args(1).length () > 2) { if (!vinitstep.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" will be ignored if fixed time stamps are given"); vinitstep = args(1).vector_value ()(1); } else if (vinitstep.is_empty ()) { vinitstep = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" not set, new value 1e-6 is used"); } // Implementation of the option MaxStep has been finished, this // option can be set by the user to another value than default value octave_value vmaxstep = odepkg_auxiliary_getmapvalue ("MaxStep", vodeopt); if (vmaxstep.is_empty () && args(1).length () == 2) { vmaxstep = (args(1).vector_value ()(1) - args(1).vector_value ()(0)) / 12.5; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxStep\" not set, new value %3.1e is used", vmaxstep.double_value ()); } // Implementation of the option Events has been finished, this // option can be set by the user to another value than default // value, odepkg_structure_check already checks for a valid value octave_value vevents = odepkg_auxiliary_getmapvalue ("Events", vodeopt); octave_value_list veveres; // We save the results of Events here // The options 'Jacobian', 'JPattern' and 'Vectorized' octave_value vjac = odepkg_auxiliary_getmapvalue ("Jacobian", vodeopt); if (!vjac.is_empty ()) vddaskrjacfun = vjac; // The option Mass will be ignored by this solver. We can't handle // Mass-matrix options with IDE problems octave_value vmass = odepkg_auxiliary_getmapvalue ("Mass", vodeopt); if (!vmass.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"Mass\" will be ignored by this solver"); // The option MStateDependence will be ignored by this solver. We // can't handle Mass-matrix options with IDE problems octave_value vmst = odepkg_auxiliary_getmapvalue ("MStateDependence", vodeopt); if (!vmst.is_empty ()) if (vmst.string_value ().compare ("weak") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MStateDependence\" will be ignored by this solver"); // The option MvPattern will be ignored by this solver. We // can't handle Mass-matrix options with IDE problems octave_value vmvpat = odepkg_auxiliary_getmapvalue ("MvPattern", vodeopt); if (!vmvpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MvPattern\" will be ignored by this solver"); // The option MvPattern will be ignored by this solver. We // can't handle Mass-matrix options with IDE problems octave_value vmsing = odepkg_auxiliary_getmapvalue ("MassSingular", vodeopt); if (!vmsing.is_empty ()) if (vmsing.string_value ().compare ("maybe") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MassSingular\" will be ignored by this solver"); // The option InitialSlope will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vinitslope = odepkg_auxiliary_getmapvalue ("InitialSlope", vodeopt); if (!vinitslope.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialSlope\" will be ignored by this solver"); // Implementation of the option MaxOrder has been finished, this // option can be set by the user to another value than default value octave_value vmaxder = odepkg_auxiliary_getmapvalue ("MaxOrder", vodeopt); if (vmaxder.is_empty ()) { vmaxder = 3; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" not set, new value 3 is used"); } else if (vmaxder.int_value () < 1) { vmaxder = 3; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" is zero, new value 3 is used"); } // The option BDF will be ignored because this is a BDF solver octave_value vbdf = odepkg_auxiliary_getmapvalue ("BDF", vodeopt); if (!vbdf.is_empty ()) if (vbdf.string_value () != "on") { vbdf = "on"; warning_with_id ("OdePkg:InvalidOption", "Option \"BDF\" set \"off\", new value \"on\" is used"); } // The option NewtonTol and MaxNewtonIterations will be ignored by // this solver, IT NEEDS TO BE CHECKED IF THE FORTRAN CORE SOLVER // CAN HANDLE THESE OPTIONS octave_value vntol = odepkg_auxiliary_getmapvalue ("NewtonTol", vodeopt); if (!vntol.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NewtonTol\" will be ignored by this solver"); octave_value vmaxnewton = odepkg_auxiliary_getmapvalue ("MaxNewtonIterations", vodeopt); if (!vmaxnewton.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" will be ignored by this solver"); /* Start MAINPROCESSING, set up all variables that are needed by this * solver and then initialize the solver function and get into the * main integration loop ********************************************************************/ NDArray vTIME = args(1).array_value (); NDArray vY = args(2).array_value (); NDArray vYPRIME = args(3).array_value (); NDArray vRTOL = vreltol.array_value (); NDArray vATOL = vabstol.array_value (); vddaskrneqn = args(2).length (); double T = vTIME(0); double TEND = vTIME(vTIME.length () - 1); double *Y = vY.fortran_vec (); double *YPRIME = vYPRIME.fortran_vec (); octave_idx_type IDID = 0; double *RTOL = vRTOL.fortran_vec (); double *ATOL = vATOL.fortran_vec (); double RPAR[1] = {0.0}; octave_idx_type IPAR[1] = {0}; octave_idx_type NRT = 0; OCTAVE_LOCAL_BUFFER (octave_idx_type, JROOT, NRT); for (octave_idx_type vcnt = 0; vcnt < NRT; vcnt++) JROOT[vcnt] = 0; octave_idx_type LRW = 60 + vddaskrneqn * (9 + vddaskrneqn) + 3 * NRT; OCTAVE_LOCAL_BUFFER (double, RWORK, LRW); for (octave_idx_type vcnt = 0; vcnt < LRW; vcnt++) RWORK[vcnt] = 0.0; octave_idx_type LIW = 40 + vddaskrneqn; OCTAVE_LOCAL_BUFFER (octave_idx_type, IWORK, LIW); for (octave_idx_type vcnt = 0; vcnt < LIW; vcnt++) IWORK[vcnt] = 0; octave_idx_type N = 20; OCTAVE_LOCAL_BUFFER (octave_idx_type, INFO, N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) INFO[vcnt] = 0; INFO[0] = 0; // Define that it is the initial first call INFO[1] = vitol; // RelTol/AbsTol are scalars or vectors INFO[2] = 1; // An intermediate output is wanted INFO[3] = 0; // Integrate behind TEND if (!vjac.is_empty ()) INFO[4] = 1; else INFO[4] = 0; // Internally calculate a Jacobian? 0..yes INFO[5] = 0; // Have a full Jacobian matrix? 0..yes INFO[6] = 1; // Use the value for maximum step size INFO[7] = 1; // The initial step size INFO[8] = 1; // Use MaxOrder 5 as default? 1..no INFO[11] = 0; // direct method (not krylov) RWORK[1] = vmaxstep.double_value (); // MaxStep value RWORK[2] = vinitstep.double_value (); // InitialStep value IWORK[2] = vmaxder.int_value (); // MaxOrder value // If the user has set an OutputFcn or an Events function then // initialize these IO-functions for further use octave_value vtim (T); octave_value vsol (vY); octave_value vyds (vYPRIME); odepkg_auxiliary_solstore (vtim, vsol, 0); if (!vplot.is_empty ()) odepkg_auxiliary_evalplotfun (vplot, voutsel, args(1), args(2), vddaskrextarg, 0); octave_value_list veveideargs; veveideargs(0) = vsol; veveideargs(1) = vyds; Cell veveidearg (veveideargs); if (!vevents.is_empty ()) odepkg_auxiliary_evaleventfun (vevents, vtim, veveidearg, vddaskrextarg, 0); // We are calling the core solver here to intialize all variables F77_XFCN (ddaskr, DDASKR, // Keep 5 arguments per line here (odepkg_ddaskr_resfcn, vddaskrneqn, T, Y, YPRIME, TEND, INFO, RTOL, ATOL, IDID, RWORK, LRW, IWORK, LIW, RPAR, IPAR, odepkg_ddaskr_jacfcn, odepkg_ddaskr_psolfcn, odepkg_ddaskr_rtfcn, NRT, JROOT)); if (IDID < 0) { odepkg_ddaskr_error (IDID); return (vretval); } // We need that variable in the following loop after calling the // core solver function and before calling the plot function ColumnVector vcres(vddaskrneqn); ColumnVector vydrs(vddaskrneqn); if (vTIME.length () == 2) { INFO[0] = 1; // Set this info variable ie. continue solving while (T < TEND) { F77_XFCN (ddaskr, DDASKR, // Keep 5 arguments per line here (odepkg_ddaskr_resfcn, vddaskrneqn, T, Y, YPRIME, TEND, INFO, RTOL, ATOL, IDID, RWORK, LRW, IWORK, LIW, RPAR, IPAR, odepkg_ddaskr_jacfcn, odepkg_ddaskr_psolfcn, odepkg_ddaskr_rtfcn, NRT, JROOT)); if (IDID < 0) { odepkg_ddaskr_error (IDID); return (vretval); } // This call of the Fortran solver has been successful so let us // plot the output and save the results for (octave_idx_type vcnt = 0; vcnt < vddaskrneqn; vcnt++) { vcres(vcnt) = Y[vcnt]; vydrs(vcnt) = YPRIME[vcnt]; } vsol = vcres; vyds = vydrs; vtim = T; if (!vevents.is_empty ()) { veveideargs(0) = vsol; veveideargs(1) = vyds; veveidearg = veveideargs; veveres = odepkg_auxiliary_evaleventfun (vevents, vtim, veveidearg, vddaskrextarg, 1); if (!veveres(0).cell_value ()(0).is_empty ()) if (veveres(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = veveres(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = veveres(0).cell_value ()(3).matrix_value (); vtim = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vsol = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); T = TEND; // let's get out here, the Events function told us to finish } } if (!vplot.is_empty ()) { if (odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vddaskrextarg, 1)) { error ("Missing error message implementation"); return (vretval); } } odepkg_auxiliary_solstore (vtim, vsol, 1); } } /* Start POSTPROCESSING, check how many arguments should be returned * to the caller and check which extra arguments have to be set *******************************************************************/ // Set up values that come from the last Fortran call and that are // needed to call the OdePkg output function a last time again for (octave_idx_type vcnt = 0; vcnt < vddaskrneqn; vcnt++) { vcres(vcnt) = Y[vcnt]; vydrs(vcnt) = YPRIME[vcnt]; } vsol = vcres; vyds = vydrs; vtim = T; veveideargs(0) = vsol; veveideargs(1) = vyds; veveidearg = veveideargs; if (!vevents.is_empty ()) odepkg_auxiliary_evaleventfun (vevents, vtim, vsol, vddaskrextarg, 2); if (!vplot.is_empty ()) odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vddaskrextarg, 2); // Return the results that have been stored in the // odepkg_auxiliary_solstore function octave_value vtres, vyres; odepkg_auxiliary_solstore (vtres, vyres, 2); // Get the stats information as an Octave_map if the option 'Stats' // has been set with odeset // "nsteps", "nfailed", "nfevals", "npds", "ndecomps", "nlinsols" octave_value_list vstatinput; vstatinput(0) = IWORK[10]; vstatinput(1) = IWORK[14]; vstatinput(2) = IWORK[11]; vstatinput(3) = IWORK[12]; vstatinput(4) = 0; vstatinput(5) = IWORK[18]; octave_value vstatinfo; if ((vstats.string_value ().compare ("on") == 0) && (nargout == 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, false); else if ((vstats.string_value ().compare ("on") == 0) && (nargout != 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, true); // Set up output arguments that depend on how many output arguments // are desired -- check the nargout variable if (nargout == 1) { Octave_map vretmap; vretmap.assign ("x", vtres); vretmap.assign ("y", vyres); vretmap.assign ("solver", "odekdi"); if (vstats.string_value ().compare ("on") == 0) vretmap.assign ("stats", vstatinfo); if (!vevents.is_empty ()) { vretmap.assign ("ie", veveres(0).cell_value ()(1)); vretmap.assign ("xe", veveres(0).cell_value ()(2)); vretmap.assign ("ye", veveres(0).cell_value ()(3)); } vretval(0) = octave_value (vretmap); } else if (nargout == 2) { vretval(0) = vtres; vretval(1) = vyres; } else if (nargout == 5) { Matrix vempty; // prepare an empty matrix vretval(0) = vtres; vretval(1) = vyres; vretval(2) = vempty; vretval(3) = vempty; vretval(4) = vempty; if (!vevents.is_empty ()) { vretval(2) = veveres(0).cell_value ()(2); vretval(3) = veveres(0).cell_value ()(3); vretval(4) = veveres(0).cell_value ()(1); } } return (vretval); } /* %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [vres] = fpol (vt, vy, vyd, varargin) %! vres = [vy(2) - vyd(1); %! (1 - vy(1)^2) * vy(2) - vy(1) - vyd(2)]; %!function [vjac, vyjc] = fjac (vt, vy, vyd, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %! vyjc = [-1, 0; 0, -1]; %!function [vjac, vyjc] = fjcc (vt, vy, vyd, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %! vyjc = sparse ([-1, 0; 0, -1]); %!function [vval, vtrm, vdir] = feve (vt, vy, vyd, varargin) %! vval = vyd; %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, vyd, varargin) %! vval = vyd; %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vref] = fref () %# The computed reference solut %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (size (vt) != [2, 1] && size (vt) != [1, 2]) %! error ('"fout" step "init"'); %! end %! elseif (isempty (vflag)) %! if (size (vt) ~= [1, 1]) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (size (vt) ~= [1, 1]) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! vsol = odekdi (1, [0, 2], [2; 0], [0; -2]); %!error %# input argument number two %! vsol = odekdi (@fpol, 1, [2; 0], [0; -2]); %!error %# input argument number three %! vsol = odekdi (@fpol, [0, 2], 1, [0; -2]); %!error %# input argument number four %! vsol = odekdi (@fpol, [0, 2], [2; 0], 1); %!test %# one output argument %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'odekdi'); %!test %# two output arguments %! [vt, vy] = odekdi (@fpol, [0, 2], [2; 0], [0; -2]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = odekdi (@fpol, [0, 2], [2; 0], [0; -2]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy,vyd) [vy(2)-vyd(1); (1-vy(1)^2)*vy(2)-vy(1)-vyd(2)]; %! vsol = odekdi (fvdb, [0, 2], [2; 0], [0; -2]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-4); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-4); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-1); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-7); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-3); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end-1)-vsol.x(end-2)], [1e-2], 1e-1); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = odekdi (@fpol, [0, 10], [2; 0], [0; -2], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'MaxStep', 0.1); %! vsol = odekdi (@fpol, [0, 10], [2; 0], [0; -2], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.49537, -0.82867, -2.67469], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'MaxStep', 0.1); %! [vt, vy, vxe, vye, vie] = odekdi (@fpol, [0, 10], [2; 0], [0; -2], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.49537, -0.82867, -2.67469], 1e-1); %! warning ('on', 'OdePkg:HideWarning'); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac, 'InitialStep', 1e-12); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for Mass option is missing %! %# test for MStateDependence option is missing %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %!test %# MaxOrder option %! vopt = odeset ('MaxOrder', 5); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# BDF option %! vopt = odeset ('BDF', 'on'); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set NewtonTol option to something else than default %! vopt = odeset ('NewtonTol', 1e-3); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set MaxNewtonIterations option to something else than default %! vopt = odeset ('MaxNewtonIterations', 2); %! vsol = odekdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! warning ('on', 'OdePkg:InvalidOption'); */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_octsolver_mebdfdae.cc0000644000176000010400000012310711711232766021476 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ /* Compile this file manually and run some tests with the following command bash:$ mkoctfile -v -Wall -W -Wshadow odepkg_octsolver_mebdfdae.cc \ odepkg_auxiliary_functions.cc cash/mebdfdae.f -o odebda.oct bash:$ octave --quiet --eval "autoload ('odebda', [pwd, '/odebda.oct']); \ test 'odepkg_octsolver_mebdfdae.cc'" If you have installed 'gfortran' or 'g95' on your computer then use the FFLAGS=-fno-automatic option because otherwise the solver function will be broken, eg. bash:$ FFLAGS="-fno-automatic ${FFLAGS}" mkoctfile -v -Wall -W \ -Wshadow odepkg_octsolver_mebdfdae.cc odepkg_auxiliary_functions.cc \ cash/mebdfdae.f -o odebda.oct octave> octave --quiet --eval "autoload ('odebda', [pwd, '/odebda.oct']); \ test 'odepkg_octsolver_mebdfdae.cc'" For an explanation about various parts of this source file cf. the source file odepkg_octsolver_odebdi.cc. The implementation of that file is very similiar to the implementation of this file. */ #include #include #include #include #include #include "odepkg_auxiliary_functions.h" typedef octave_idx_type (*odepkg_mebdfdae_usrtype) (const octave_idx_type& N, const double& T, const double* Y, double* YDOT, const octave_idx_type* IPAR, const double* RPAR, const octave_idx_type& IERR); typedef octave_idx_type (*odepkg_mebdfdae_jactype) (const double& T, const double* Y, double* PD, const octave_idx_type& N, const octave_idx_type& MEBAND, const octave_idx_type* IPAR, const double* RPAR, const octave_idx_type& IERR); typedef octave_idx_type (*odepkg_mebdfdae_masstype) (const octave_idx_type& N, double* AM, const octave_idx_type* MASBND, const double* RPAR, const octave_idx_type* IPAR, const octave_idx_type& IERR); extern "C" { F77_RET_T F77_FUNC (mebdf, MEBDF) // 3 arguments per line (const octave_idx_type& N, const double& T0, const double& HO, const double* Y0, const double& TOUT, const double& TEND, const octave_idx_type& MF, octave_idx_type& IDID, const octave_idx_type& LOUT, const octave_idx_type& LWORK, const double* WORK, const octave_idx_type& LIWORK, const octave_idx_type* IWORK, const octave_idx_type* MBND, const octave_idx_type* MASBND, const octave_idx_type& MAXDER, const octave_idx_type& ITOL, const double* RTOL, const double* ATOL, const double* RPAR, const octave_idx_type* IPAR, odepkg_mebdfdae_usrtype, odepkg_mebdfdae_jactype, odepkg_mebdfdae_masstype, octave_idx_type& IERR); } // extern "C" static octave_value_list vmebdfdaeextarg; static octave_value vmebdfdaeodefun; static octave_value vmebdfdaejacfun; static octave_value vmebdfdaemass; static octave_value vmebdfdaemassstate; octave_idx_type odepkg_mebdfdae_usrfcn (const octave_idx_type& N, const double& T, const double* Y, double* YDOT, GCC_ATTR_UNUSED const octave_idx_type* IPAR, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type& IERR) { // Copy the values that come from the Fortran function element wise, // otherwise Octave will crash if these variables will be freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Fill the variable for the input arguments before evaluating the // function that keeps the set of implicit differential equations octave_value_list varin; varin(0) = T; varin(1) = A; for (octave_idx_type vcnt = 0; vcnt < vmebdfdaeextarg.length (); vcnt++) varin(vcnt+2) = vmebdfdaeextarg(vcnt); octave_value_list vout = feval (vmebdfdaeodefun.function_value (), varin, 1); // Return the results from the function evaluation to the Fortran // solver, again copy them and don't just create a Fortran vector ColumnVector vcol = vout(0).column_vector_value (); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) YDOT[vcnt] = vcol(vcnt); return (true); } octave_idx_type odepkg_mebdfdae_jacfcn (const double& T, const double* Y, double* PD, const octave_idx_type& N, GCC_ATTR_UNUSED const octave_idx_type& MEBAND, GCC_ATTR_UNUSED const octave_idx_type* IPAR, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type& IERR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Jacobian function octave_value vt = octave_value (T); octave_value vy = octave_value (A); octave_value_list vout = odepkg_auxiliary_evaljacode (vmebdfdaejacfun, vt, vy, vmebdfdaeextarg); // Computes the NxN iteration matrix or partial derivatives for the // Fortran solver of the form PD=DG/DY+1/CON*(DG/DY') // octave_value vbdov = vout(0) + 1/CON * vout(1); Matrix vbd = vout(0).matrix_value (); for (octave_idx_type vrow = 0; vrow < N; vrow++) for (octave_idx_type vcol = 0; vcol < N; vcol++) PD[vrow+vcol*N] = vbd (vrow, vcol); // Don't know what my mistake is but the following code line never // worked for me (ie. the solver crashes Octave if it is used) // PD = vbd.fortran_vec (); return (true); } octave_idx_type odepkg_mebdfdae_massfcn (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* MASBND, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, GCC_ATTR_UNUSED const octave_idx_type& IERR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = 0.0; // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (0.0); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evalmassode (vmebdfdaemass, vmebdfdaemassstate, vt, vy, vmebdfdaeextarg); Matrix vam = vout.matrix_value (); for (octave_idx_type vrow = 0; vrow < N; vrow++) for (octave_idx_type vcol = 0; vcol < N; vcol++) { AM[vrow+vcol*N] = vam (vrow, vcol); } return (true); } octave_idx_type odepkg_mebdfdae_error (octave_idx_type verr) { switch (verr) { case 0: break; // Everything is fine case -1: error_with_id ("OdePkg:InternalError", "Integration was halted after failing to pass one error test (error \ occured in \"mebdfi\" core solver function with error number \"%d\")", verr); break; case -2: error_with_id ("OdePkg:InternalError", "Integration was halted after failing to pass a repeated error test \ after a successful initialisation step or because of an invalid option \ in RelTol or AbsTol (error occured in \"mebdfi\" core solver function with \ error number \"%d\")", verr); break; case -3: error_with_id ("OdePkg:InternalError", "Integration was halted after failing to achieve a corrector \ convergence even after reducing the step size h by a factor of 1e-10 \ (error occured in \"mebdfi\" core solver function with error number \ \"%d\")", verr); break; case -4: error_with_id ("OdePkg:InternalError", "Immediate halt because of illegal number or illegal values of input \ arguments (error occured in the \"mebdfi\" core solver function with \ error number \"%d\")", verr); break; case -5: error_with_id ("OdePkg:InternalError", "Idid was -1 on input (error occured in \"mebdfi\" core solver function \ with error number \"%d\")", verr); break; case -6: error_with_id ("OdePkg:InternalError", "Maximum number of allowed integration steps exceeded (error occured in \ \"mebdfi\" core solver function with error number \"%d\")", verr); break; case -7: error_with_id ("OdePkg:InternalError", "Stepsize grew too small (error occured in \"mebdfi\" core solver \ function with error number \"%d\")", verr); break; case -11: error_with_id ("OdePkg:InternalError", "Insufficient real workspace for the integration (error occured in \ \"mebdfi\" core solver function with error number \"%d\")", verr); break; case -12: error_with_id ("OdePkg:InternalError", "Insufficient integer workspace for the integration (error occured in \ \"mebdfi\" core solver function with error number \"%d\")", verr); break; default: error_with_id ("OdePkg:InternalError", "Unknown error (error occured in \"mebdfi\" core solver function with \ error number \"%d\")", verr); break; } return (true); } // PKG_ADD: autoload ("odebda", "dldsolver.oct"); DEFUN_DLD (odebda, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Command} {[@var{}] =} odebda (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{sol}] =} odebda (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odebda (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ \n\ This function file can be used to solve a set of stiff ordinary differential equations (ODEs) and stiff differential algebraic equations (DAEs). This function file is a wrapper file that uses Jeff Cash's Fortran solver @file{mebdfdae.f}.\n\ \n\ If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}.\n\ \n\ If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}.\n\ \n\ If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector.\n\ \n\ For example,\n\ @example\n\ function y = odepkg_equations_lorenz (t, x)\n\ y = [10 * (x(2) - x(1));\n\ x(1) * (28 - x(3));\n\ x(1) * x(2) - 8/3 * x(3)];\n\ endfunction\n\ \n\ vopt = odeset (\"InitialStep\", 1e-3, \"MaxStep\", 1e-1, \\\n\ \"OutputFcn\", @@odephas3, \"Refine\", 5);\n\ odebda (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt);\n\ @end example\n\ @end deftypefn\n\ \n\ @seealso{odepkg}") { octave_idx_type nargin = args.length (); // The number of input arguments octave_value_list vretval; // The cell array of return args Octave_map vodeopt; // The OdePkg options structure // Check number and types of all the input arguments if (nargin < 3) { print_usage (); return (vretval); } // If args(0)==function_handle is valid then set the vmebdfdaeodefun // variable that has been defined "static" before if (!args(0).is_function_handle () && !args(0).is_inline_function ()) { error_with_id ("OdePkg:InvalidArgument", "First input argument must be a valid function handle"); return (vretval); } else // We store the args(0) argument in the static variable vmebdfdaeodefun vmebdfdaeodefun = args(0); // Check if the second input argument is a valid vector describing // the time window of solving, it may be of length 2 or longer if (args(1).is_scalar_type () || !odepkg_auxiliary_isvector (args(1))) { error_with_id ("OdePkg:InvalidArgument", "Second input argument must be a valid vector"); return (vretval); } // Check if the third input argument is a valid vector describing // the initial values of the variables of the IDEs if (!odepkg_auxiliary_isvector (args(2))) { error_with_id ("OdePkg:InvalidArgument", "Third input argument must be a valid vector"); return (vretval); } // Check if there are further input arguments ie. the options // structure and/or arguments that need to be passed to the // OutputFcn, Events and/or Jacobian etc. if (nargin >= 4) { // Fourth input argument != OdePkg option, need a default structure if (!args(3).is_map ()) { octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure for (octave_idx_type vcnt = 3; vcnt < nargin; vcnt++) vmebdfdaeextarg(vcnt-3) = args(vcnt); // Save arguments in vmebdfdaeextarg } // Fourth input argument == OdePkg option, extra input args given too else if (nargin > 4) { octave_value_list varin; varin(0) = args(3); varin(1) = "odebda"; octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create structure from args(4) for (octave_idx_type vcnt = 4; vcnt < nargin; vcnt++) vmebdfdaeextarg(vcnt-4) = args(vcnt); // Save extra arguments } // Fourth input argument == OdePkg option, no extra input args given else { octave_value_list varin; varin(0) = args(3); varin(1) = "odebda"; // Check structure octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create a default structure } } // if (nargin >= 4) else { // if nargin == 3, everything else has been checked before octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure } /* Start PREPROCESSING, ie. check which options have been set and * print warnings if there are options that can't be handled by this * solver or have not been implemented yet *******************************************************************/ // Implementation of the option RelTol has been finished, this // option can be set by the user to another value than default value octave_value vreltol = odepkg_auxiliary_getmapvalue ("RelTol", vodeopt); if (vreltol.is_empty ()) { vreltol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"RelTol\" not set, new value %3.1e is used", vreltol.double_value ()); } // vreltol.print (octave_stdout, true); return (vretval); if (!vreltol.is_scalar_type ()) { if (vreltol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"RelTol\" must be the same as the number of equations"); return (vretval); } } // Implementation of the option AbsTol has been finished, this // option can be set by the user to another value than default value octave_value vabstol = odepkg_auxiliary_getmapvalue ("AbsTol", vodeopt); if (vabstol.is_empty ()) { vabstol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"AbsTol\" not set, new value %3.1e is used", vabstol.double_value ()); } // vabstol.print (octave_stdout, true); return (vretval); if (!vabstol.is_scalar_type ()) { if (vabstol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"AbsTol\" must be the same as the number of equations"); return (vretval); } } // Setting the tolerance type that depends on the types (scalar or // vector) of the options RelTol and AbsTol octave_idx_type vitol = 0; if (vreltol.is_scalar_type () && vabstol.is_scalar_type ()) vitol = 2; else if (vreltol.is_scalar_type () && !vabstol.is_scalar_type ()) vitol = 3; else if (!vreltol.is_scalar_type () && vabstol.is_scalar_type ()) vitol = 4; else if (!vreltol.is_scalar_type () && !vabstol.is_scalar_type ()) vitol = 5; // The option NormControl will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnorm = odepkg_auxiliary_getmapvalue ("NormControl", vodeopt); if (!vnorm.is_empty ()) if (vnorm.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"NormControl\" will be ignored by this solver"); // The option NonNegative will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnneg = odepkg_auxiliary_getmapvalue ("NonNegative", vodeopt); if (!vnneg.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NonNegative\" will be ignored by this solver"); // Implementation of the option OutputFcn has been finished, this // option can be set by the user to another value than default value octave_value vplot = odepkg_auxiliary_getmapvalue ("OutputFcn", vodeopt); if (vplot.is_empty () && nargout == 0) vplot = "odeplot"; // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value octave_value voutsel = odepkg_auxiliary_getmapvalue ("OutputSel", vodeopt); // The option Refine will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vrefine = odepkg_auxiliary_getmapvalue ("Refine", vodeopt); if (vrefine.int_value () != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"Refine\" will be ignored by this solver"); // Implementation of the option Stats has been finished, this option // can be set by the user to another value than default value octave_value vstats = odepkg_auxiliary_getmapvalue ("Stats", vodeopt); // Implementation of the option InitialStep has been finished, this // option can be set by the user to another value than default value octave_value vinitstep = odepkg_auxiliary_getmapvalue ("InitialStep", vodeopt); if (args(1).length () > 2) { if (!vinitstep.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" will be ignored if fixed time stamps are given"); vinitstep = args(1).vector_value ()(1); } if (vinitstep.is_empty ()) { vinitstep = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" not set, new value %3.1e is used", vinitstep.double_value ()); } // Implementation of the option MaxStep has been finished, this // option can be set by the user to another value than default value octave_value vmaxstep = odepkg_auxiliary_getmapvalue ("MaxStep", vodeopt); if (vmaxstep.is_empty () && args(1).length () == 2) { vmaxstep = (args(1).vector_value ()(1) - args(1).vector_value ()(0)) / 12.5; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxStep\" not set, new value %3.1e is used", vmaxstep.double_value ()); } // Implementation of the option Events has been finished, this // option can be set by the user to another value than default // value, odepkg_structure_check already checks for a valid value octave_value vevents = odepkg_auxiliary_getmapvalue ("Events", vodeopt); octave_value_list veveres; // We save the results of Events here // The options 'Jacobian', 'JPattern' and 'Vectorized' octave_value vjac = odepkg_auxiliary_getmapvalue ("Jacobian", vodeopt); octave_idx_type vmebdfdaejac = 22; // We need to set this if no Jac available if (!vjac.is_empty ()) { vmebdfdaejacfun = vjac; vmebdfdaejac = 21; } // Implementation of the option 'Mass' has been finished, these // options can be set by the user to another value than default vmebdfdaemass = odepkg_auxiliary_getmapvalue ("Mass", vodeopt); octave_idx_type vmebdfdaemas = 0; if (!vmebdfdaemass.is_empty ()) { vmebdfdaemas = 1; if (vmebdfdaemass.is_function_handle () || vmebdfdaemass.is_inline_function ()) warning_with_id ("OdePkg:InvalidOption", "Option \"Mass\" only supports constant mass matrices M() and not M(t,y)"); } // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option vmebdfdaemassstate = odepkg_auxiliary_getmapvalue ("MStateDependence", vodeopt); if (!vmebdfdaemassstate.is_empty ()) if (vmebdfdaemassstate.string_value ().compare ("weak") != 0) // 'weak' is default warning_with_id ("OdePkg:InvalidOption", "Option \"MStateDependence\" will be ignored by this solver"); // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmvpat = odepkg_auxiliary_getmapvalue ("MvPattern", vodeopt); if (!vmvpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MvPattern\" will be ignored by this solver"); // The option MassSingular will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmsing = odepkg_auxiliary_getmapvalue ("MassSingular", vodeopt); if (!vmsing.is_empty ()) if (vmsing.string_value ().compare ("maybe") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MassSingular\" will be ignored by this solver"); // The option InitialSlope will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vinitslope = odepkg_auxiliary_getmapvalue ("InitialSlope", vodeopt); if (!vinitslope.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialSlope\" will be ignored by this solver"); // Implementation of the option MaxOrder has been finished, this // option can be set by the user to another value than default value octave_value vmaxder = odepkg_auxiliary_getmapvalue ("MaxOrder", vodeopt); if (vmaxder.is_empty ()) { vmaxder = 3; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" not set, new value %1d is used", vmaxder.int_value ()); } if (vmaxder.int_value () < 1) { vmaxder = 3; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" is zero, new value %1d is used", vmaxder.int_value ()); } // The option BDF will be ignored because this is a BDF solver octave_value vbdf = odepkg_auxiliary_getmapvalue ("BDF", vodeopt); if (vbdf.is_string ()) if (vbdf.string_value () != "on") { vbdf = "on"; warning_with_id ("OdePkg:InvalidOption", "Option \"BDF\" set \"off\", new value \"on\" is used"); } // The option NewtonTol and MaxNewtonIterations will be ignored by // this solver, IT NEEDS TO BE CHECKED IF THE FORTRAN CORE SOLVER // CAN HANDLE THESE OPTIONS octave_value vntol = odepkg_auxiliary_getmapvalue ("NewtonTol", vodeopt); if (!vntol.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NewtonTol\" will be ignored by this solver"); octave_value vmaxnewton = odepkg_auxiliary_getmapvalue ("MaxNewtonIterations", vodeopt); if (!vmaxnewton.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" will be ignored by this solver"); /* Start MAINPROCESSING, set up all variables that are needed by this * solver and then initialize the solver function and get into the * main integration loop ********************************************************************/ ColumnVector vTIME (args(1).vector_value ()); NDArray vRTOL = vreltol.array_value (); NDArray vATOL = vabstol.array_value (); NDArray vY0 = args(2).array_value (); octave_idx_type N = args(2).length (); double T0 = vTIME(0); double HO = vinitstep.double_value (); double *Y0 = vY0.fortran_vec (); double TOUT = T0 + vinitstep.double_value (); double TEND = vTIME(vTIME.length ()-1); octave_idx_type MF = vmebdfdaejac; octave_idx_type IDID = 1; octave_idx_type LOUT = 6; // Logical output channel "not opened" octave_idx_type LWORK = 42*N+3*N*N+4; OCTAVE_LOCAL_BUFFER (double, WORK, LWORK); for (octave_idx_type vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; octave_idx_type LIWORK = N+14; OCTAVE_LOCAL_BUFFER (octave_idx_type, IWORK, LIWORK); for (octave_idx_type vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; octave_idx_type MBND[4] = {N, N, N, N}; octave_idx_type MASBND[4] = {0, N, 0, N}; if (!vmebdfdaemass.is_empty ()) MASBND[0] = 1; octave_idx_type MAXDER = vmaxder.int_value (); octave_idx_type ITOL = vitol; double *RTOL = vRTOL.fortran_vec (); double *ATOL = vATOL.fortran_vec (); double RPAR[1] = {0.0}; octave_idx_type IPAR[1] = {0}; octave_idx_type IERR = 0; IWORK[0] = N; // Number of variables of index 1 IWORK[1] = 0; // Number of variables of index 2 IWORK[2] = 0; // Number of variables of index 3 IWORK[13] = 1000000; // The maximum number of steps allowed // Check if the user has set some of the options "OutputFcn", "Events" // etc. and initialize the plot, events and the solstore functions octave_value vtim (T0); octave_value vsol (vY0); odepkg_auxiliary_solstore (vtim, vsol, 0); if (!vplot.is_empty ()) odepkg_auxiliary_evalplotfun (vplot, voutsel, args(1), args(2), vmebdfdaeextarg, 0); if (!vevents.is_empty ()) odepkg_auxiliary_evaleventfun (vevents, vtim, args(2), vmebdfdaeextarg, 0); // We are calling the core solver here to intialize all variables F77_XFCN (mebdf, MEBDF, // Keep 5 arguments per line here (N, T0, HO, Y0, TOUT, TEND, MF, IDID, LOUT, LWORK, WORK, LIWORK, IWORK, MBND, MASBND, MAXDER, ITOL, RTOL, ATOL, RPAR, IPAR, odepkg_mebdfdae_usrfcn, odepkg_mebdfdae_jacfcn, odepkg_mebdfdae_massfcn, IERR)); if (IDID < 0) { odepkg_mebdfdae_error (IDID); return (vretval); } // We need that variable in the following loop after calling the // core solver function and before calling the plot function ColumnVector vcres(N); if (vTIME.length () == 2) { // Before we are entering the solver loop replace the first time // stamp value with FirstStep = (InitTime - InitStep) TOUT = TOUT - vinitstep.double_value (); while (TOUT < TEND) { // Calculate the next time stamp for that an solution is required TOUT = TOUT + vmaxstep.double_value (); TOUT = (TOUT > TEND ? TEND : TOUT); // Call the core Fortran solver again and again and check if an // exception is encountered, set IDID = 2 every time to hit // every point of time that is required exactly IDID = 2; F77_XFCN (mebdf, MEBDF, // Keep 5 arguments per line here (N, T0, HO, Y0, TOUT, TEND, MF, IDID, LOUT, LWORK, WORK, LIWORK, IWORK, MBND, MASBND, MAXDER, ITOL, RTOL, ATOL, RPAR, IPAR, odepkg_mebdfdae_usrfcn, odepkg_mebdfdae_jacfcn, odepkg_mebdfdae_massfcn, IERR)); if (IDID < 0) { odepkg_mebdfdae_error (IDID); return (vretval); } // This call of the Fortran solver has been successful so let us // plot the output and save the results for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) vcres(vcnt) = Y0[vcnt]; vsol = vcres; vtim = TOUT; if (!vevents.is_empty ()) { veveres = odepkg_auxiliary_evaleventfun (vevents, vtim, vsol, vmebdfdaeextarg, 1); if (!veveres(0).cell_value ()(0).is_empty ()) if (veveres(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = veveres(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = veveres(0).cell_value ()(3).matrix_value (); vtim = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vsol = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); TOUT = TEND; // let's get out here, the Events function told us to finish } } if (!vplot.is_empty ()) { if (odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vmebdfdaeextarg, 1)) { error ("Missing error message implementation"); return (vretval); } } odepkg_auxiliary_solstore (vtim, vsol, 1); } } else { // if (vTIME.length () > 2) we have all the time values needed volatile octave_idx_type vtimecnt = 1; octave_idx_type vtimelen = vTIME.length (); while (vtimecnt < vtimelen) { vtimecnt++; TOUT = vTIME(vtimecnt-1); // Call the core Fortran solver again and again and check if an // exception is encountered, set IDID = 2 every time to hit // every point of time that is required exactly IDID = 2; F77_XFCN (mebdf, MEBDF, // Keep 5 arguments per line here (N, T0, HO, Y0, TOUT, TEND, MF, IDID, LOUT, LWORK, WORK, LIWORK, IWORK, MBND, MASBND, MAXDER, ITOL, RTOL, ATOL, RPAR, IPAR, odepkg_mebdfdae_usrfcn, odepkg_mebdfdae_jacfcn, odepkg_mebdfdae_massfcn, IERR)); if (IDID < 0) { odepkg_mebdfdae_error (IDID); return (vretval); } // The last call of the Fortran solver has been successful so // let us plot the output and save the results for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) vcres(vcnt) = Y0[vcnt]; vsol = vcres; vtim = TOUT; if (!vevents.is_empty ()) { veveres = odepkg_auxiliary_evaleventfun (vevents, vtim, vsol, vmebdfdaeextarg, 1); if (!veveres(0).cell_value ()(0).is_empty ()) if (veveres(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = veveres(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = veveres(0).cell_value ()(3).matrix_value (); vtim = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vsol = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); vtimecnt = vtimelen; // let's get out here, the Events function told us to finish } } if (!vplot.is_empty ()) { if (odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vmebdfdaeextarg, 1)) { error ("Missing error message implementation"); return (vretval); } } odepkg_auxiliary_solstore (vtim, vsol, 1); } } /* Start POSTPROCESSING, check how many arguments should be returned * to the caller and check which extra arguments have to be set *******************************************************************/ // Set up values that come from the last Fortran call and that are // needed to call the OdePkg output function one last time again for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) vcres(vcnt) = Y0[vcnt]; vsol = vcres; vtim = TOUT; if (!vevents.is_empty ()) odepkg_auxiliary_evaleventfun (vevents, vtim, vsol, vmebdfdaeextarg, 2); if (!vplot.is_empty ()) odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vmebdfdaeextarg, 2); // Return the results that have been stored in the // odepkg_auxiliary_solstore function octave_value vtres, vyres; odepkg_auxiliary_solstore (vtres, vyres, 2); // odepkg_auxiliary_solstore (vtres, vyres, voutsel, 100); // Get the stats information as an Octave_map if the option 'Stats' // has been set with odeset // "nsteps", "nfailed", "nfevals", "npds", "ndecomps", "nlinsols" octave_value_list vstatinput; vstatinput(0) = IWORK[4]; vstatinput(1) = IWORK[5]; vstatinput(2) = IWORK[6]; vstatinput(3) = IWORK[7]; vstatinput(4) = IWORK[8]; vstatinput(5) = IWORK[9]; octave_value vstatinfo; if (vstats.string_value () == "on" && (nargout == 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, false); else if (vstats.string_value () == "on" && (nargout != 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, true); // Set up output arguments that depends on how many output arguments // are desired by the caller if (nargout == 1) { Octave_map vretmap; vretmap.assign ("x", vtres); vretmap.assign ("y", vyres); vretmap.assign ("solver", "odebda"); if (vstats.string_value () == "on") vretmap.assign ("stats", vstatinfo); if (!vevents.is_empty ()) { vretmap.assign ("ie", veveres(0).cell_value ()(1)); vretmap.assign ("xe", veveres(0).cell_value ()(2)); vretmap.assign ("ye", veveres(0).cell_value ()(3)); } vretval(0) = octave_value (vretmap); } else if (nargout == 2) { vretval(0) = vtres; vretval(1) = vyres; } else if (nargout == 5) { Matrix vempty; // prepare an empty matrix vretval(0) = vtres; vretval(1) = vyres; vretval(2) = vempty; vretval(3) = vempty; vretval(4) = vempty; if (!vevents.is_empty ()) { vretval(2) = veveres(0).cell_value ()(2); vretval(3) = veveres(0).cell_value ()(3); vretval(4) = veveres(0).cell_value ()(1); } } return (vretval); } /* %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference solut %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (size (vt) != [2, 1] && size (vt) != [1, 2]) %! error ('"fout" step "init"'); %! end %! elseif (isempty (vflag)) %! if (size (vt) ~= [1, 1]) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (size (vt) ~= [1, 1]) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = odebda (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = odebda (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = odebda (@flor, [0 25], 1); %!test %# one output argument %! vsol = odebda (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'odebda'); %!test %# two output arguments %! [vt, vy] = odebda (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = odebda (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = odebda (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = odebda (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = odebda (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-5); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-5); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = odebda (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = odebda (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = odebda (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'RelTol', 1e-10); %! vsol = odebda (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.63352, -0.98874, -1.93801], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = odebda (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.63352, -0.98874, -1.93801], 1e-1); %! warning ('on', 'OdePkg:HideWarning'); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %!test %# BDF option set "off" %! vopt = odeset ('BDF', 'off'); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set NewtonTol option to something else than default %! vopt = odeset ('NewtonTol', 1e-3); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set MaxNewtonIterations option to something else than default %! vopt = odeset ('MaxNewtonIterations', 2); %! vsol = odebda (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! warning ('on', 'OdePkg:InvalidOption'); */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_octsolver_mebdfi.cc0000644000176000010400000013656711711232766021213 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ /* Compile this file manually and run some tests with the following command bash:$ mkoctfile -v -Wall -W -Wshadow odepkg_octsolver_mebdfi.cc \ odepkg_auxiliary_functions.cc cash/mebdfi.f -o odebdi.oct octave> octave --quiet --eval "autoload ('odebdi', [pwd, '/odebdi.oct']); \ test 'odepkg_octsolver_mebdfi.cc'" If you have installed 'gfortran' or 'g95' on your computer then use the FFLAGS=-fno-automatic option because otherwise the solver function will be broken, eg. bash:$ FFLAGS="-fno-automatic ${FFLAGS}" mkoctfile -v -Wall -W \ -Wshadow odepkg_octsolver_mebdfi.cc odepkg_auxiliary_functions.cc \ cash/mebdfi.f -o odebdi.oct octave> octave --quiet --eval "autoload ('odebdi', [pwd, '/odebdi.oct']); \ test 'odepkg_octsolver_mebdfi.cc'" */ #include #include #include #include #include #include "odepkg_auxiliary_functions.h" /* -*- texinfo -*- * @subsection Source File @file{odepkg_octsolver_mebdfi.cc} * * @deftp {Typedef} {octave_idx_type (*odepkg_mebdfi_usrtype)} * This @code{typedef} is used to define the input and output arguments of the user function for the IDE problem that is further needed by the Fortran core solver @code{mebdfi}. The implementation of this @code{typedef} is * * @example * typedef octave_idx_type (*odepkg_mebdfi_usrtype) * (const octave_idx_type& N, const double& T, const double* Y, * double* DELTA, const double* YPRIME, const octave_idx_type* IPAR, * const double* RPAR, const octave_idx_type& IERR); * @end example * @end deftp */ typedef octave_idx_type (*odepkg_mebdfi_usrtype) (const octave_idx_type& N, const double& T, const double* Y, double* DELTA, const double* YPRIME, const octave_idx_type* IPAR, const double* RPAR, const octave_idx_type& IERR); /* -*- texinfo -*- * @deftp {Typedef} {octave_idx_type (*odepkg_mebdfi_jactype)} * * This @code{typedef} is used to define the input and output arguments of the @code{Jacobian} function for the IDE problem that is further needed by the Fortran core solver @code{mebdfi}. The implementation of this @code{typedef} is * * @example * typedef octave_idx_type (*odepkg_mebdfi_jactype) * (const double& T, const double* Y, double* PD, * const octave_idx_type& N, const double* YPRIME, * const octave_idx_type* MBND, const double& CON, * const octave_idx_type* IPAR, const double* RPAR, * const octave_idx_type& IERR); * @end example * @end deftp */ typedef octave_idx_type (*odepkg_mebdfi_jactype) // 3 arguments per line (const double& T, const double* Y, double* PD, const octave_idx_type& N, const double* YPRIME, const octave_idx_type* MBND, const double& CON, const octave_idx_type* IPAR, const double* RPAR, const octave_idx_type& IERR); extern "C" { /* -*- texinfo -*- * @deftp {Prototype} {F77_RET_T F77_FUNC (mebdfi, MEBDFI)} (const octave_idx_type& N, const double& T0, const double& HO, const double* Y0, const double* YPRIME, const double& TOUT, const double& TEND, const octave_idx_type& MF, octave_idx_type& IDID, const octave_idx_type& LOUT, const octave_idx_type& LWORK, const double* WORK, const octave_idx_type& LIWORK, const octave_idx_type* IWORK, const octave_idx_type* MBND, const octave_idx_type& MAXDER, const octave_idx_type& ITOL, const double* RTOL, const double* ATOL, const double* RPAR, const octave_idx_type* IPAR, odepkg_mebdfi_jactype, odepkg_mebdfi_usrtype, octave_idx_type& IERR); * * The prototype @code{F77_FUNC (mebdfi, MEBDFI)} is used to represent the information about the Fortran core solver @code{mebdfi} that is defined in the Fortran source file @file{mebdfi.f} (cf. the Fortran source file @file{mebdfi.f} for further details). * @end deftp */ F77_RET_T F77_FUNC (mebdfi, MEBDFI) // 3 arguments per line (const octave_idx_type& N, const double& T0, const double& HO, const double* Y0, const double* YPRIME, const double& TOUT, const double& TEND, const octave_idx_type& MF, octave_idx_type& IDID, const octave_idx_type& LOUT, const octave_idx_type& LWORK, const double* WORK, const octave_idx_type& LIWORK, const octave_idx_type* IWORK, const octave_idx_type* MBND, const octave_idx_type& MAXDER, const octave_idx_type& ITOL, const double* RTOL, const double* ATOL, const double* RPAR, const octave_idx_type* IPAR, odepkg_mebdfi_jactype, odepkg_mebdfi_usrtype, octave_idx_type& IERR); } /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value_list} {vmebdfiextarg} * * This static variable is used to store the extra arguments that are needed by some or by all of the @code{OutputFcn}, the @code{Jacobian} function and the @code{Events} function while solving the IDE problem. * @end deftypevr */ static octave_value_list vmebdfiextarg; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {*vmebdfiodefun} * * This static variable is used to store the value for the user function that defines the set of IDEs. * @end deftypevr */ static octave_value vmebdfiodefun; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vmebdfijacfun} * * This static variable is used to store the value for the @code{Jacobian} function or the @code{Jacobian} matrix that is needed if Jacobian evaluation should be performed. * @end deftypevr */ static octave_value vmebdfijacfun; /* -*- texinfo -*- * @deftypefn {Function} {octave_idx_type} {odepkg_mebdfi_usrfcn} (const octave_idx_type& N, const double& T, const double* Y, double* DELTA, const double* YPRIME, GCC_ATTR_UNUSED const octave_idx_type* IPAR, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type& IERR) * * Return @code{true} if the evaluation of the user function was successful, return @code{false} otherwise. This function is directly called from the Fortran core solver @code{mebdfi}. The input arguments of this function are * * @itemize @minus * @item @var{N}: The number of equations that are defined for the IDE--problem * @item @var{T}: The actual time stamp for the current function evaluation * @item @var{Y}: The function values from the last successful integration step of length @var{N} * @item @var{DELTA}: The residual vector that needs to be calculated of length @var{N} * @item @var{YPRIME}: The derivative values from the last successful integration step of length @var{N} * @item @var{IPAR}: The integer parameters that are passed to the user function (unused) * @item @var{RPAR}: The real parameters that are passed to the user function (unused) * @item @var{IERR}: The error flag that can be set on each evaluation (unused) * @end itemize * @end deftypefn */ octave_idx_type odepkg_mebdfi_usrfcn (const octave_idx_type& N, const double& T, const double* Y, double* DELTA, const double* YPRIME, GCC_ATTR_UNUSED const octave_idx_type* IPAR, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type& IERR) { // Copy the values that come from the Fortran function element wise, // otherwise Octave will crash if these variables will be freed ColumnVector A(N), APRIME(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { A(vcnt) = Y[vcnt]; APRIME(vcnt) = YPRIME[vcnt]; } // Fill the variable for the input arguments before evaluating the // function that keeps the set of implicit differential equations octave_value_list varin; varin(0) = T; varin(1) = A; varin(2) = APRIME; for (octave_idx_type vcnt = 0; vcnt < vmebdfiextarg.length (); vcnt++) varin(vcnt+3) = vmebdfiextarg(vcnt); octave_value_list vout = feval (vmebdfiodefun.function_value (), varin, 1); // Return the results from the function evaluation to the Fortran // solver, again copy them and don't just create a Fortran vector ColumnVector vcol = vout(0).column_vector_value (); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) DELTA[vcnt] = vcol(vcnt); return (true); } /* -*- texinfo -*- * @deftypefn {Function} {octave_idx_type} {odepkg_mebdfi_jacfcn} (const double& T, const double* Y, double* PD, const octave_idx_type& N, const double* YPRIME, GCC_ATTR_UNUSED const octave_idx_type* MBND, const double& CON, GCC_ATTR_UNUSED const octave_idx_type* IPAR, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type& IERR) * * Return @code{true} if the evaluation of the Jacobian function (that is defined for a special IDE problem in Octave) was successful, otherwise return @code{false}. This function is directly called from the Fortran core solver @code{mebdfi}. The input arguments of this function are * * @itemize @minus * @item @var{T}: The actual time stamp for the current function evaluation * @item @var{Y}: The function values from the last successful integration step of length @var{N} * @item @var{PD}: The values of partial derivatives of the Jacobian matrix of size @var{N} * @item @var{N}: The number of equations that are defined for the IDE--problem * @item @var{YPRIME}: The derivative values from the last successful integration step of length @var{N} * @item @var{MBND}: A vector of size 4 describing the sizes of a banded Jacobian (unused) * @item @var{CON}: A constant value that is set before the evaluation of the Jacobian function * @item @var{IPAR}: The integer parameters that are passed to the user function (unused) * @item @var{RPAR}: The real parameters that are passed to the user function (unused) * @item @var{IERR}: The error flag that can be set on each evaluation (unused) * @end itemize * @end deftypefn */ octave_idx_type odepkg_mebdfi_jacfcn (const double& T, const double* Y, double* PD, const octave_idx_type& N, const double* YPRIME, GCC_ATTR_UNUSED const octave_idx_type* MBND, const double& CON, GCC_ATTR_UNUSED const octave_idx_type* IPAR, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type& IERR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N), APRIME(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { A(vcnt) = Y[vcnt]; APRIME(vcnt) = YPRIME[vcnt]; } // Set the values that are needed as input arguments before calling // the Jacobian function octave_value vt = octave_value (T); octave_value vy = octave_value (A); octave_value vdy = octave_value (APRIME); octave_value_list vout = odepkg_auxiliary_evaljacide (vmebdfijacfun, vt, vy, vdy, vmebdfiextarg); // Computes the NxN iteration matrix or partial derivatives for the // Fortran solver of the form PD=DG/DY+1/CON*(DG/DY') octave_value vbdov = vout(0) + 1/CON * vout(1); Matrix vbd = vbdov.matrix_value (); for (octave_idx_type vrow = 0; vrow < N; vrow++) for (octave_idx_type vcol = 0; vcol < N; vcol++) PD[vrow+vcol*N] = vbd (vrow, vcol); // Don't know what my mistake is but the following code line never // worked for me (ie. the solver crashes Octave if it is used) // PD = vbd.fortran_vec (); return (true); } /* -*- texinfo -*- * @deftypefn {Function} octave_idx_type odepkg_mebdfi_error (octave_idx_type verr) * TODO * @end deftypefn */ octave_idx_type odepkg_mebdfi_error (octave_idx_type verr) { switch (verr) { case 0: break; // Everything is fine case -1: error_with_id ("OdePkg:InternalError", "Integration was halted after failing to pass one error test (error \ occured in \"mebdfi\" core solver function with error number \"%d\")", verr); break; case -2: error_with_id ("OdePkg:InternalError", "Integration was halted after failing to pass a repeated error test \ after a successful initialisation step or because of an invalid option \ in RelTol or AbsTol (error occured in \"mebdfi\" core solver function with \ error number \"%d\")", verr); break; case -3: error_with_id ("OdePkg:InternalError", "Integration was halted after failing to achieve a corrector \ convergence even after reducing the step size h by a factor of 1e-10 \ (error occured in \"mebdfi\" core solver function with error number \ \"%d\")", verr); break; case -4: error_with_id ("OdePkg:InternalError", "Immediate halt because of illegal number or illegal values of input \ arguments (error occured in the \"mebdfi\" core solver function with \ error number \"%d\")", verr); break; case -5: error_with_id ("OdePkg:InternalError", "Idid was -1 on input (error occured in \"mebdfi\" core solver function \ with error number \"%d\")", verr); break; case -6: error_with_id ("OdePkg:InternalError", "Maximum number of allowed integration steps exceeded (error occured in \ \"mebdfi\" core solver function with error number \"%d\")", verr); break; case -7: error_with_id ("OdePkg:InternalError", "Stepsize grew too small (error occured in \"mebdfi\" core solver \ function with error number \"%d\")", verr); break; case -11: error_with_id ("OdePkg:InternalError", "Insufficient real workspace for the integration (error occured in \ \"mebdfi\" core solver function with error number \"%d\")", verr); break; case -12: error_with_id ("OdePkg:InternalError", "Insufficient integer workspace for the integration (error occured in \ \"mebdfi\" core solver function with error number \"%d\")", verr); break; default: error_with_id ("OdePkg:InternalError", "Unknown error (error occured in \"mebdfi\" core solver function with \ error number \"%d\")", verr); break; } return (true); } /* -*- texinfo -*- * @deftp {Function} {DEFUN_DLD} (odebdi, args, nargout, 'help string') * @findex odebdi * * Return the results of the solving process of the IDE problem from the Fortran core solver @code{mebdfi} to the caller function (cf. @command{help odebdi} within Octave for further details about this function). the Argument @var{odebdi} is the name of the function that can be used in Octave and @var{'help string'} is the help text that is displayed if the command @command{help odebdi} is called from Octave. The input arguments of this function are * @itemize @minus * @item @var{args}: The input arguments in form of an @code{octave_value_list} * @item @var{nargout}: The number of output arguments that are required * @end itemize * @end deftp */ // PKG_ADD: autoload ("odebdi", "dldsolver.oct"); DEFUN_DLD (odebdi, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Command} {[@var{}] =} odebdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}])\n\ @deftypefnx {Command} {[@var{sol}] =} odebdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}])\n\ @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odebdi (@var{@@fun}, @var{slot}, @var{y0}, @var{dy0}, [@var{opt}], [@var{P1}, @var{P2}, @dots{}])\n\ \n\ This function file can be used to solve a set of stiff implicit differential equations (IDEs). This function file is a wrapper file that uses Jeff Cash's Fortran solver @file{mebdfi.f}.\n\ \n\ If this function is called with no return argument then plot the solution over time in a figure window while solving the set of IDEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{y0} is a double vector that defines the initial values of the states, @var{dy0} is a double vector that defines the initial values of the derivatives, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}.\n\ \n\ If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of IDEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}.\n\ \n\ If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector.\n\ \n\ For example,\n\ @example\n\ function res = odepkg_equations_ilorenz (t, y, yd)\n\ res = [10 * (y(2) - y(1)) - yd(1);\n\ y(1) * (28 - y(3)) - yd(2);\n\ y(1) * y(2) - 8/3 * y(3) - yd(3)];\n\ endfunction\n\ \n\ vopt = odeset (\"InitialStep\", 1e-3, \"MaxStep\", 1e-1, \\\n\ \"OutputFcn\", @@odephas3, \"Refine\", 5);\n\ odebdi (@@odepkg_equations_ilorenz, [0, 25], [3 15 1], \\\n\ [120 81 42.333333], vopt);\n\ @end example\n\ @end deftypefn\n\ \n\ @seealso{odepkg}") { octave_idx_type nargin = args.length (); // The number of input arguments octave_value_list vretval; // The cell array of return args Octave_map vodeopt; // The OdePkg options structure // Check number and types of all the input arguments if (nargin < 4) { print_usage (); return (vretval); } // If args(0)==function_handle is valid then set the vmebdfiodefun // variable that has been defined "static" before if (!args(0).is_function_handle () && !args(0).is_inline_function ()) { error_with_id ("OdePkg:InvalidArgument", "First input argument must be a valid function handle"); return (vretval); } else // We store the args(0) argument in the static variable vmebdfiodefun vmebdfiodefun = args(0); // Check if the second input argument is a valid vector describing // the time window of solving, it may be of length 2 or longer if (args(1).is_scalar_type () || !odepkg_auxiliary_isvector (args(1))) { error_with_id ("OdePkg:InvalidArgument", "Second input argument must be a valid vector"); return (vretval); } // Check if the third input argument is a valid vector describing // the initial values of the variables of the IDEs if (!odepkg_auxiliary_isvector (args(2))) { error_with_id ("OdePkg:InvalidArgument", "Third input argument must be a valid vector"); return (vretval); } // Check if the fourth input argument is a valid vector describing // the initial values of the derivatives of the differential equations if (!odepkg_auxiliary_isvector (args(3))) { error_with_id ("OdePkg:InvalidArgument", "Fourth input argument must be a valid vector"); return (vretval); } // Check if the third and the fourth input argument (check for // vector already was successful before) have the same length if (args(2).length () != args(3).length ()) { error_with_id ("OdePkg:InvalidArgument", "Third and fourth input argument must have the same length"); return (vretval); } // Check if there are further input arguments ie. the options // structure and/or arguments that need to be passed to the // OutputFcn, Events and/or Jacobian etc. if (nargin >= 5) { // Fifth input argument != OdePkg option, need a default structure if (!args(4).is_map ()) { octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure for (octave_idx_type vcnt = 4; vcnt < nargin; vcnt++) vmebdfiextarg(vcnt-4) = args(vcnt); // Save arguments in vmebdfiextarg } // Fifth input argument == OdePkg option, extra input args given too else if (nargin > 5) { octave_value_list varin; varin(0) = args(4); varin(1) = "odebdi"; octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create structure of args(4) for (octave_idx_type vcnt = 5; vcnt < nargin; vcnt++) vmebdfiextarg(vcnt-5) = args(vcnt); // Save extra arguments } // Fifth input argument == OdePkg option, no extra input args given else { octave_value_list varin; varin(0) = args(4); varin(1) = "odebdi"; // Check structure octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create a default structure } } // if (nargin >= 5) else { // if nargin == 4, everything else has been checked before octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure } /* Start PREPROCESSING, ie. check which options have been set and * print warnings if there are options that can't be handled by this * solver or have not been implemented yet *******************************************************************/ // Implementation of the option RelTol has been finished, this // option can be set by the user to another value than default value octave_value vreltol = odepkg_auxiliary_getmapvalue ("RelTol", vodeopt); if (vreltol.is_empty ()) { vreltol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"RelTol\" not set, new value %3.1e is used", vreltol.double_value ()); } // vreltol.print (octave_stdout, true); return (vretval); if (!vreltol.is_scalar_type ()) { if (vreltol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"RelTol\" must be the same as the number of equations"); return (vretval); } } // Implementation of the option AbsTol has been finished, this // option can be set by the user to another value than default value octave_value vabstol = odepkg_auxiliary_getmapvalue ("AbsTol", vodeopt); if (vabstol.is_empty ()) { vabstol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"AbsTol\" not set, new value %3.1e is used", vabstol.double_value ()); } // vabstol.print (octave_stdout, true); return (vretval); if (!vabstol.is_scalar_type ()) { if (vabstol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"AbsTol\" must be the same as the number of equations"); return (vretval); } } // Setting the tolerance type that depends on the types (scalar or // vector) of the options RelTol and AbsTol octave_idx_type vitol = 0; if (vreltol.is_scalar_type () && vabstol.is_scalar_type ()) vitol = 2; else if (vreltol.is_scalar_type () && !vabstol.is_scalar_type ()) vitol = 3; else if (!vreltol.is_scalar_type () && vabstol.is_scalar_type ()) vitol = 4; else if (!vreltol.is_scalar_type () && !vabstol.is_scalar_type ()) vitol = 5; // The option NormControl will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnorm = odepkg_auxiliary_getmapvalue ("NormControl", vodeopt); if (!vnorm.is_empty ()) if (vnorm.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"NormControl\" will be ignored by this solver"); // The option NonNegative will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnneg = odepkg_auxiliary_getmapvalue ("NonNegative", vodeopt); if (!vnneg.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NonNegative\" will be ignored by this solver"); // Implementation of the option OutputFcn has been finished, this // option can be set by the user to another value than default value octave_value vplot = odepkg_auxiliary_getmapvalue ("OutputFcn", vodeopt); if (vplot.is_empty () && nargout == 0) vplot = "odeplot"; // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value octave_value voutsel = odepkg_auxiliary_getmapvalue ("OutputSel", vodeopt); // The option Refine will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vrefine = odepkg_auxiliary_getmapvalue ("Refine", vodeopt); if (vrefine.int_value () != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"Refine\" will be ignored by this solver"); // Implementation of the option Stats has been finished, this option // can be set by the user to another value than default value octave_value vstats = odepkg_auxiliary_getmapvalue ("Stats", vodeopt); // Implementation of the option InitialStep has been finished, this // option can be set by the user to another value than default value octave_value vinitstep = odepkg_auxiliary_getmapvalue ("InitialStep", vodeopt); if (args(1).length () > 2) { if (!vinitstep.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" will be ignored if fixed time stamps are given"); vinitstep = args(1).vector_value ()(1); } if (vinitstep.is_empty ()) { vinitstep = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" not set, new value %3.1e is used", vinitstep.double_value ()); } // Implementation of the option MaxStep has been finished, this // option can be set by the user to another value than default value octave_value vmaxstep = odepkg_auxiliary_getmapvalue ("MaxStep", vodeopt); if (vmaxstep.is_empty () && args(1).length () == 2) { vmaxstep = (args(1).vector_value ()(1) - args(1).vector_value ()(0)) / 12.5; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxStep\" not set, new value %3.1e is used", vmaxstep.double_value ()); } // Implementation of the option Events has been finished, this // option can be set by the user to another value than default // value, odepkg_structure_check already checks for a valid value octave_value vevents = odepkg_auxiliary_getmapvalue ("Events", vodeopt); octave_value_list veveres; // We save the results of Events here // The options 'Jacobian', 'JPattern' and 'Vectorized' octave_value vjac = odepkg_auxiliary_getmapvalue ("Jacobian", vodeopt); octave_idx_type vmebdfijac = 22; // We need to set this if no Jac available if (!vjac.is_empty ()) { vmebdfijacfun = vjac; vmebdfijac = 21; } // The option Mass will be ignored by this solver. We can't handle // Mass-matrix options with IDE problems octave_value vmass = odepkg_auxiliary_getmapvalue ("Mass", vodeopt); if (!vmass.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"Mass\" will be ignored by this solver"); // The option MStateDependence will be ignored by this solver. We // can't handle Mass-matrix options with IDE problems octave_value vmst = odepkg_auxiliary_getmapvalue ("MStateDependence", vodeopt); if (!vmst.is_empty ()) if (vmst.string_value ().compare ("weak") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MStateDependence\" will be ignored by this solver"); // The option MvPattern will be ignored by this solver. We // can't handle Mass-matrix options with IDE problems octave_value vmvpat = odepkg_auxiliary_getmapvalue ("MvPattern", vodeopt); if (!vmvpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MvPattern\" will be ignored by this solver"); // The option MvPattern will be ignored by this solver. We // can't handle Mass-matrix options with IDE problems octave_value vmsing = odepkg_auxiliary_getmapvalue ("MassSingular", vodeopt); if (!vmsing.is_empty ()) if (vmsing.string_value ().compare ("maybe") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MassSingular\" will be ignored by this solver"); // The option InitialSlope will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vinitslope = odepkg_auxiliary_getmapvalue ("InitialSlope", vodeopt); if (!vinitslope.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialSlope\" will be ignored by this solver"); // Implementation of the option MaxOrder has been finished, this // option can be set by the user to another value than default value octave_value vmaxder = odepkg_auxiliary_getmapvalue ("MaxOrder", vodeopt); if (vmaxder.is_empty ()) { vmaxder = 3; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" not set, new value %1d is used", vmaxder.int_value ()); } if (vmaxder.int_value () < 1) { vmaxder = 3; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" is zero, new value %1d is used", vmaxder.int_value ()); } // The option BDF will be ignored because this is a BDF solver octave_value vbdf = odepkg_auxiliary_getmapvalue ("BDF", vodeopt); if (vbdf.is_string ()) if (vbdf.string_value () != "on") { vbdf = "on"; warning_with_id ("OdePkg:InvalidOption", "Option \"BDF\" set \"off\", new value \"on\" is used"); } // The option NewtonTol and MaxNewtonIterations will be ignored by // this solver, IT NEEDS TO BE CHECKED IF THE FORTRAN CORE SOLVER // CAN HANDLE THESE OPTIONS octave_value vntol = odepkg_auxiliary_getmapvalue ("NewtonTol", vodeopt); if (!vntol.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NewtonTol\" will be ignored by this solver"); octave_value vmaxnewton = odepkg_auxiliary_getmapvalue ("MaxNewtonIterations", vodeopt); if (!vmaxnewton.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" will be ignored by this solver"); /* Start MAINPROCESSING, set up all variables that are needed by this * solver and then initialize the solver function and get into the * main integration loop ********************************************************************/ ColumnVector vTIME (args(1).vector_value ()); NDArray vRTOL = vreltol.array_value (); NDArray vATOL = vabstol.array_value (); NDArray vY0 = args(2).array_value (); NDArray vYPRIME = args(3).array_value (); octave_idx_type N = args(2).length (); double T0 = vTIME(0); double HO = vinitstep.double_value (); double *Y0 = vY0.fortran_vec (); double *YPRIME = vYPRIME.fortran_vec (); double TOUT = T0 + vinitstep.double_value (); double TEND = vTIME(vTIME.length ()-1); octave_idx_type MF = vmebdfijac; octave_idx_type IDID = 1; octave_idx_type LOUT = 6; // Logical output channel "not opened" octave_idx_type LWORK = 32*N+2*N*N+3; OCTAVE_LOCAL_BUFFER (double, WORK, LWORK); for (octave_idx_type vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; octave_idx_type LIWORK = N+14; OCTAVE_LOCAL_BUFFER (octave_idx_type, IWORK, LIWORK); for (octave_idx_type vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; octave_idx_type MBND[4] = {N, N, N, N}; octave_idx_type MAXDER = vmaxder.int_value (); octave_idx_type ITOL = vitol; double *RTOL = vRTOL.fortran_vec (); double *ATOL = vATOL.fortran_vec (); double RPAR[1] = {0.0}; octave_idx_type IPAR[1] = {0}; octave_idx_type IERR = 0; IWORK[13] = 1000000; // The maximum number of steps allowed // Check if the user has set some of the options "OutputFcn", "Events" // etc. and initialize the plot, events and the solstore functions octave_value vtim (T0); octave_value vsol (vY0); octave_value vyds (vYPRIME); odepkg_auxiliary_solstore (vtim, vsol, 0); if (!vplot.is_empty ()) odepkg_auxiliary_evalplotfun (vplot, voutsel, args(1), args(2), vmebdfiextarg, 0); octave_value_list veveideargs; veveideargs(0) = vsol; veveideargs(1) = vyds; Cell veveidearg (veveideargs); if (!vevents.is_empty ()) odepkg_auxiliary_evaleventfun (vevents, vtim, veveidearg, vmebdfiextarg, 0); // We are calling the core solver here to intialize all variables F77_XFCN (mebdfi, MEBDFI, // Keep 5 arguments per line here (N, T0, HO, Y0, YPRIME, TOUT, TEND, MF, IDID, LOUT, LWORK, WORK, LIWORK, IWORK, MBND, MAXDER, ITOL, RTOL, ATOL, RPAR, IPAR, odepkg_mebdfi_jacfcn, odepkg_mebdfi_usrfcn, IERR)); if (IDID < 0) { odepkg_mebdfi_error (IDID); return (vretval); } // We need that variable in the following loop after calling the // core solver function and before calling the plot function ColumnVector vcres(N); ColumnVector vydrs(N); if (vTIME.length () == 2) { // Before we are entering the solver loop replace the first time // stamp value with FirstStep = (InitTime - InitStep) TOUT = TOUT - vinitstep.double_value (); while (TOUT < TEND) { // Calculate the next time stamp for that an solution is required TOUT = TOUT + vmaxstep.double_value (); TOUT = (TOUT > TEND ? TEND : TOUT); // Call the core Fortran solver again and again and check if an // exception is encountered, set IDID = 2 every time to hit // every point of time that is required exactly IDID = 2; F77_XFCN (mebdfi, MEBDFI, // Keep 5 arguments per line here (N, T0, HO, Y0, YPRIME, TOUT, TEND, MF, IDID, LOUT, LWORK, WORK, LIWORK, IWORK, MBND, MAXDER, ITOL, RTOL, ATOL, RPAR, IPAR, odepkg_mebdfi_jacfcn, odepkg_mebdfi_usrfcn, IERR)); if (IDID < 0) { odepkg_mebdfi_error (IDID); return (vretval); } // This call of the Fortran solver has been successful so let us // plot the output and save the results for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { vcres(vcnt) = Y0[vcnt]; vydrs(vcnt) = YPRIME[vcnt]; } vsol = vcres; vyds = vydrs; vtim = TOUT; if (!vevents.is_empty ()) { veveideargs(0) = vsol; veveideargs(1) = vyds; veveidearg = veveideargs; veveres = odepkg_auxiliary_evaleventfun (vevents, vtim, veveidearg, vmebdfiextarg, 1); if (!veveres(0).cell_value ()(0).is_empty ()) if (veveres(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = veveres(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = veveres(0).cell_value ()(3).matrix_value (); vtim = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vsol = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); TOUT = TEND; // let's get out here, the Events function told us to finish } } if (!vplot.is_empty ()) { if (odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vmebdfiextarg, 1)) { error ("Missing error message implementation"); return (vretval); } } odepkg_auxiliary_solstore (vtim, vsol, 1); } } else { // if (vTIME.length () > 2) we have all the time values needed volatile octave_idx_type vtimecnt = 1; octave_idx_type vtimelen = vTIME.length () - 1; while (vtimecnt < vtimelen) { vtimecnt++; TOUT = vTIME(vtimecnt); // Call the core Fortran solver again and again and check if an // exception is encountered, set IDID = 2 every time to hit // every point of time that is required exactly IDID = 2; F77_XFCN (mebdfi, MEBDFI, // Keep 5 arguments per line here (N, T0, HO, Y0, YPRIME, TOUT, TEND, MF, IDID, LOUT, LWORK, WORK, LIWORK, IWORK, MBND, MAXDER, ITOL, RTOL, ATOL, RPAR, IPAR, odepkg_mebdfi_jacfcn, odepkg_mebdfi_usrfcn, IERR)); if (IDID < 0) { odepkg_mebdfi_error (IDID); return (vretval); } // The last call of the Fortran solver has been successful so // let us plot the output and save the results for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { vcres(vcnt) = Y0[vcnt]; vydrs(vcnt) = YPRIME[vcnt]; } vsol = vcres; vyds = vydrs; vtim = TOUT; if (!vevents.is_empty ()) { veveideargs(0) = vsol; veveideargs(1) = vyds; veveidearg = veveideargs; veveres = odepkg_auxiliary_evaleventfun (vevents, vtim, veveidearg, vmebdfiextarg, 1); if (!veveres(0).cell_value ()(0).is_empty ()) if (veveres(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = veveres(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = veveres(0).cell_value ()(3).matrix_value (); vtim = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vsol = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); vtimecnt = vtimelen; // let's get out here, the Events function told us to finish } } if (!vplot.is_empty ()) { if (odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vmebdfiextarg, 1)) { error ("Missing error message implementation"); return (vretval); } } odepkg_auxiliary_solstore (vtim, vsol, 1); } } /* Start POSTPROCESSING, check how many arguments should be returned * to the caller and check which extra arguments have to be set *******************************************************************/ // Set up values that come from the last Fortran call and that are // needed to call the OdePkg output function one last time again for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { vcres(vcnt) = Y0[vcnt]; vydrs(vcnt) = YPRIME[vcnt]; } vsol = vcres; vyds = vydrs; vtim = TOUT; veveideargs(0) = vsol; veveideargs(1) = vyds; veveidearg = veveideargs; if (!vevents.is_empty ()) odepkg_auxiliary_evaleventfun (vevents, vtim, veveidearg, vmebdfiextarg, 2); if (!vplot.is_empty ()) odepkg_auxiliary_evalplotfun (vplot, voutsel, vtim, vsol, vmebdfiextarg, 2); // Return the results that have been stored in the // odepkg_auxiliary_solstore function octave_value vtres, vyres; odepkg_auxiliary_solstore (vtres, vyres, 2); // odepkg_auxiliary_solstore (vtres, vyres, voutsel, 100); // Get the stats information as an Octave_map if the option 'Stats' // has been set with odeset octave_value_list vstatinput; vstatinput(0) = IWORK[4]; vstatinput(1) = IWORK[5]; vstatinput(2) = IWORK[6]; vstatinput(3) = IWORK[7]; vstatinput(4) = IWORK[8]; vstatinput(5) = IWORK[9]; octave_value vstatinfo; if (vstats.string_value () == "on" && (nargout == 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, false); else if (vstats.string_value () == "on" && (nargout != 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, true); // Set up output arguments that depends on how many output arguments // are desired by the caller if (nargout == 1) { Octave_map vretmap; vretmap.assign ("x", vtres); vretmap.assign ("y", vyres); vretmap.assign ("solver", "odebdi"); if (vstats.string_value () == "on") vretmap.assign ("stats", vstatinfo); if (!vevents.is_empty ()) { vretmap.assign ("ie", veveres(0).cell_value ()(1)); vretmap.assign ("xe", veveres(0).cell_value ()(2)); vretmap.assign ("ye", veveres(0).cell_value ()(3)); } vretval(0) = octave_value (vretmap); } else if (nargout == 2) { vretval(0) = vtres; vretval(1) = vyres; } else if (nargout == 5) { Matrix vempty; // prepare an empty matrix vretval(0) = vtres; vretval(1) = vyres; vretval(2) = vempty; vretval(3) = vempty; vretval(4) = vempty; if (!vevents.is_empty ()) { vretval(2) = veveres(0).cell_value ()(2); vretval(3) = veveres(0).cell_value ()(3); vretval(4) = veveres(0).cell_value ()(1); } } return (vretval); } /* %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [vres] = fpol (vt, vy, vyd, varargin) %! vres = [vy(2) - vyd(1); %! (1 - vy(1)^2) * vy(2) - vy(1) - vyd(2)]; %!function [vjac, vyjc] = fjac (vt, vy, vyd, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %! vyjc = [-1, 0; 0, -1]; %!function [vjac, vyjc] = fjcc (vt, vy, vyd, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %! vyjc = sparse ([-1, 0; 0, -1]); %!function [vval, vtrm, vdir] = feve (vt, vy, vyd, varargin) %! vval = vyd; %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, vyd, varargin) %! vval = vyd; %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vref] = fref () %# The computed reference solut %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (size (vt) != [2, 1] && size (vt) != [1, 2]) %! error ('"fout" step "init"'); %! end %! elseif (isempty (vflag)) %! if (size (vt) ~= [1, 1]) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (size (vt) ~= [1, 1]) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! vsol = odebdi (1, [0, 2], [2; 0], [0; -2]); %!error %# input argument number two %! vsol = odebdi (@fpol, 1, [2; 0], [0; -2]); %!error %# input argument number three %! vsol = odebdi (@fpol, [0, 2], 1, [0; -2]); %!error %# input argument number four %! vsol = odebdi (@fpol, [0, 2], [2; 0], 1); %!test %# one output argument %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'odebdi'); %!test %# two output arguments %! [vt, vy] = odebdi (@fpol, [0, 2], [2; 0], [0; -2]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = odebdi (@fpol, [0, 2], [2; 0], [0; -2]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy,vyd) [vy(2)-vyd(1); (1-vy(1)^2)*vy(2)-vy(1)-vyd(2)]; %! vsol = odebdi (fvdb, [0, 2], [2; 0], [0; -2]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-5); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-1); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-3); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = odebdi (@fpol, [0, 10], [2; 0], [0; -2], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'MaxStep', 0.1); %! vsol = odebdi (@fpol, [0, 10], [2; 0], [0; -2], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.49537, -0.82867, -2.67469], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'MaxStep', 0.1); %! [vt, vy, vxe, vye, vie] = odebdi (@fpol, [0, 10], [2; 0], [0; -2], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.49537, -0.82867, -2.67469], 1e-1); %! warning ('on', 'OdePkg:HideWarning'); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %# test for Mass option is missing %! %# test for MStateDependence option is missing %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %!test %# MaxOrder option %! vopt = odeset ('MaxOrder', 3); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# BDF option %! vopt = odeset ('BDF', 'off'); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set NewtonTol option to something else than default %! vopt = odeset ('NewtonTol', 1e-3); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set MaxNewtonIterations option to something else than default %! vopt = odeset ('MaxNewtonIterations', 2); %! vsol = odebdi (@fpol, [0, 2], [2; 0], [0; -2], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! warning ('on', 'OdePkg:InvalidOption'); */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_octsolver_radau.cc0000644000176000010400000011437111711232766021046 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ /* Compile this file manually and run some tests with the following command bash:~$ mkoctfile -v -Wall -W -Wshadow odepkg_octsolver_radau.cc \ odepkg_auxiliary_functions.cc hairer/radau.f hairer/dc_decsol.f \ hairer/decsol.f -o ode2r.oct octave> octave --quiet --eval "autoload ('ode2r', [pwd, '/ode2r.oct']); \ test 'odepkg_octsolver_radau.cc'" For an explanation about various parts of this source file cf. the source file odepkg_octsolver_rodas.cc. The implementation of that file is very similiar to the implementation of this file. */ #include #include #include #include #include #include "odepkg_auxiliary_functions.h" typedef octave_idx_type (*odepkg_radau_usrtype) (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_radau_jactype) (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_radau_masstype) (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_radau_soltype) (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* CONT, const octave_idx_type* LRC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN); extern "C" { F77_RET_T F77_FUNC (radau, RADAU) (const octave_idx_type& N, odepkg_radau_usrtype, const double& X, const double* Y, const double& XEND, const double& H, const double* RTOL, const double* ATOL, const octave_idx_type& ITOL, odepkg_radau_jactype, const octave_idx_type& IJAC, const octave_idx_type& MLJAC, const octave_idx_type& MUJAC, odepkg_radau_masstype, const octave_idx_type& IMAS, const octave_idx_type& MLMAS, const octave_idx_type& MUMAS, odepkg_radau_soltype, const octave_idx_type& IOUT, const double* WORK, const octave_idx_type& LWORK, const octave_idx_type* IWORK, const octave_idx_type& LIWORK, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, const octave_idx_type& IDID); double F77_FUNC (contra, CONTRA) (const octave_idx_type& I, const double& S, const double* CONT, const octave_idx_type* LRC); } // extern "C" static octave_value_list vradauextarg; static octave_value vradauodefun; static octave_value vradaujacfun; static octave_value vradauevefun; static octave_value_list vradauevesol; static octave_value vradaupltfun; static octave_value vradauoutsel; static octave_value vradaurefine; static octave_value vradaumass; static octave_value vradaumassstate; octave_idx_type odepkg_radau_usrfcn (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element wise, // otherwise Octave will crash if these variables will be freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { A(vcnt) = Y[vcnt]; // octave_stdout << "I am here Y[" << vcnt << "] " << Y[vcnt] << std::endl; // octave_stdout << "I am here T " << X << std::endl; } // Fill the variable for the input arguments before evaluating the // function that keeps the set of differential algebraic equations octave_value_list varin; varin(0) = X; varin(1) = A; for (octave_idx_type vcnt = 0; vcnt < vradauextarg.length (); vcnt++) varin(vcnt+2) = vradauextarg(vcnt); octave_value_list vout = feval (vradauodefun.function_value (), varin, 1); // Return the results from the function evaluation to the Fortran // solver, again copy them and don't just create a Fortran vector ColumnVector vcol = vout(0).column_vector_value (); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) F[vcnt] = vcol(vcnt); return (true); } octave_idx_type odepkg_radau_jacfcn (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (X); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evaljacode (vradaujacfun, vt, vy, vradauextarg); Matrix vdfy = vout.matrix_value (); for (octave_idx_type vcol = 0; vcol < N; vcol++) for (octave_idx_type vrow = 0; vrow < N; vrow++) DFY[vrow+vcol*N] = vdfy (vrow, vcol); return (true); } F77_RET_T odepkg_radau_massfcn (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = 0.0; // warning_with_id ("OdePkg:InvalidFunctionCall", // "Radau can only handle M()=const Mass matrices"); // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (0.0); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evalmassode (vradaumass, vradaumassstate, vt, vy, vradauextarg); Matrix vam = vout.matrix_value (); for (octave_idx_type vrow = 0; vrow < N; vrow++) for (octave_idx_type vcol = 0; vcol < N; vcol++) AM[vrow+vcol*N] = vam (vrow, vcol); return (true); } octave_idx_type odepkg_radau_solfcn (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* CONT, const octave_idx_type* LRC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Output function, the solstore function or the Events function octave_value vt = octave_value (X); octave_value vy = octave_value (A); // Check if an 'Events' function has been set by the user if (!vradauevefun.is_empty ()) { vradauevesol = odepkg_auxiliary_evaleventfun (vradauevefun, vt, vy, vradauextarg, 1); if (!vradauevesol(0).cell_value ()(0).is_empty ()) if (vradauevesol(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = vradauevesol(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = vradauevesol(0).cell_value ()(3).matrix_value (); vt = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vy = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); IRTRN = (vradauevesol(0).cell_value ()(0).int_value () ? -1 : 0); } } // Save the solutions that come from the Fortran core solver if this // is not the initial first call to this function if (NR > 1) odepkg_auxiliary_solstore (vt, vy, 1); // Check if an 'OutputFcn' has been set by the user (including the // values of the options for 'OutputSel' and 'Refine') if (!vradaupltfun.is_empty ()) { if (vradaurefine.int_value () > 0) { ColumnVector B(N); double vtb = 0.0; for (octave_idx_type vcnt = 1; vcnt < vradaurefine.int_value (); vcnt++) { // Calculate time stamps between XOLD and X and get the // results at these time stamps vtb = (X - XOLD) * vcnt / vradaurefine.int_value () + XOLD; for (octave_idx_type vcou = 0; vcou < N; vcou++) B(vcou) = F77_FUNC (contra, CONTRA) (vcou+1, vtb, CONT, LRC); // Evaluate the 'OutputFcn' with the approximated values from // the F77_FUNC before the output of the results is done octave_value vyr = octave_value (B); octave_value vtr = octave_value (vtb); odepkg_auxiliary_evalplotfun (vradaupltfun, vradauoutsel, vtr, vyr, vradauextarg, 1); } } // Evaluate the 'OutputFcn' with the results from the solver, if // the OutputFcn returns true then set a negative value in IRTRN IRTRN = - odepkg_auxiliary_evalplotfun (vradaupltfun, vradauoutsel, vt, vy, vradauextarg, 1); } return (true); } // PKG_ADD: autoload ("ode2r", "dldsolver.oct"); DEFUN_DLD (ode2r, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Command} {[@var{}] =} ode2r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{sol}] =} ode2r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode2r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ \n\ This function file can be used to solve a set of stiff ordinary differential equations (ODEs) and stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{radau.f}.\n\ \n\ If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}.\n\ \n\ If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}.\n\ \n\ If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector.\n\ \n\ For example,\n\ @example\n\ function y = odepkg_equations_lorenz (t, x)\n\ y = [10 * (x(2) - x(1));\n\ x(1) * (28 - x(3));\n\ x(1) * x(2) - 8/3 * x(3)];\n\ endfunction\n\ \n\ vopt = odeset (\"InitialStep\", 1e-3, \"MaxStep\", 1e-1, \\\n\ \"OutputFcn\", @@odephas3, \"Refine\", 5);\n\ ode2r (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt);\n\ @end example\n\ @end deftypefn\n\ \n\ @seealso{odepkg}") { octave_idx_type nargin = args.length (); // The number of input arguments octave_value_list vretval; // The cell array of return args Octave_map vodeopt; // The OdePkg options structure // Check number and types of all input arguments if (nargin < 3) { print_usage (); return (vretval); } // If args(0)==function_handle is valid then set the vradauodefun // variable that has been defined "static" before if (!args(0).is_function_handle () && !args(0).is_inline_function ()) { error_with_id ("OdePkg:InvalidArgument", "First input argument must be a valid function handle"); return (vretval); } else // We store the args(0) argument in the static variable vradauodefun vradauodefun = args(0); // Check if the second input argument is a valid vector describing // the time window that should be solved, it may be of length 2 ONLY if (args(1).is_scalar_type () || !odepkg_auxiliary_isvector (args(1))) { error_with_id ("OdePkg:InvalidArgument", "Second input argument must be a valid vector"); return (vretval); } // Check if the thirt input argument is a valid vector describing // the initial values of the variables of the differential equations if (!odepkg_auxiliary_isvector (args(2))) { error_with_id ("OdePkg:InvalidArgument", "Third input argument must be a valid vector"); return (vretval); } // Check if there are further input arguments ie. the options // structure and/or arguments that need to be passed to the // OutputFcn, Events and/or Jacobian etc. if (nargin >= 4) { // Fourth input argument != OdePkg option, need a default structure if (!args(3).is_map ()) { octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure for (octave_idx_type vcnt = 3; vcnt < nargin; vcnt++) vradauextarg(vcnt-3) = args(vcnt); // Save arguments in vradauextarg } // Fourth input argument == OdePkg option, extra input args given too else if (nargin > 4) { octave_value_list varin; varin(0) = args(3); varin(1) = "ode2r"; octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create structure from args(4) for (octave_idx_type vcnt = 4; vcnt < nargin; vcnt++) vradauextarg(vcnt-4) = args(vcnt); // Save extra arguments } // Fourth input argument == OdePkg option, no extra input args given else { octave_value_list varin; varin(0) = args(3); varin(1) = "ode2r"; // Check structure octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create a default structure } } // if (nargin >= 4) else { // if nargin == 3, everything else has been checked before octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure } /* Start PREPROCESSING, ie. check which options have been set and * print warnings if there are options that can't be handled by this * solver or have not been implemented yet *******************************************************************/ // Implementation of the option RelTol has been finished, this // option can be set by the user to another value than default value octave_value vreltol = odepkg_auxiliary_getmapvalue ("RelTol", vodeopt); if (vreltol.is_empty ()) { vreltol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"RelTol\" not set, new value %3.1e is used", vreltol.double_value ()); } // vreltol.print (octave_stdout, true); return (vretval); if (!vreltol.is_scalar_type ()) { if (vreltol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"RelTol\" must be the same as the number of equations"); return (vretval); } } // Implementation of the option AbsTol has been finished, this // option can be set by the user to another value than default value octave_value vabstol = odepkg_auxiliary_getmapvalue ("AbsTol", vodeopt); if (vabstol.is_empty ()) { vabstol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"AbsTol\" not set, new value %3.1e is used", vabstol.double_value ()); } // vabstol.print (octave_stdout, true); return (vretval); if (!vabstol.is_scalar_type ()) { if (vabstol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"AbsTol\" must be the same as the number of equations"); return (vretval); } } // Setting the tolerance type that depends on the types (scalar or // vector) of the options RelTol and AbsTol octave_idx_type vitol = 0; if (vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 0; else if (!vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 1; else { error_with_id ("OdePkg:InvalidOption", "Values of \"RelTol\" and \"AbsTol\" must have same length"); return (vretval); } // The option NormControl will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnorm = odepkg_auxiliary_getmapvalue ("NormControl", vodeopt); if (!vnorm.is_empty ()) if (vnorm.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"NormControl\" will be ignored by this solver"); // The option NonNegative will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnneg = odepkg_auxiliary_getmapvalue ("NonNegative", vodeopt); if (!vnneg.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NonNegative\" will be ignored by this solver"); // Implementation of the option OutputFcn has been finished, this // option can be set by the user to another value than default value vradaupltfun = odepkg_auxiliary_getmapvalue ("OutputFcn", vodeopt); if (vradaupltfun.is_empty () && nargout == 0) vradaupltfun = "odeplot"; // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vradauoutsel = odepkg_auxiliary_getmapvalue ("OutputSel", vodeopt); // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vradaurefine = odepkg_auxiliary_getmapvalue ("Refine", vodeopt); // Implementation of the option Stats has been finished, this option // can be set by the user to another value than default value octave_value vstats = odepkg_auxiliary_getmapvalue ("Stats", vodeopt); // Implementation of the option InitialStep has been finished, this // option can be set by the user to another value than default value octave_value vinitstep = odepkg_auxiliary_getmapvalue ("InitialStep", vodeopt); if (args(1).length () > 2) { error_with_id ("OdePkg:InvalidOption", "Fixed time stamps are not supported by this solver"); } if (vinitstep.is_empty ()) { vinitstep = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" not set, new value %3.1e is used", vinitstep.double_value ()); } // Implementation of the option MaxStep has been finished, this // option can be set by the user to another value than default value octave_value vmaxstep = odepkg_auxiliary_getmapvalue ("MaxStep", vodeopt); if (vmaxstep.is_empty () && args(1).length () == 2) { vmaxstep = (args(1).vector_value ()(1) - args(1).vector_value ()(0)) / 12.5; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxStep\" not set, new value %3.1e is used", vmaxstep.double_value ()); } // Implementation of the option Events has been finished, this // option can be set by the user to another value than default // value, odepkg_structure_check already checks for a valid value vradauevefun = odepkg_auxiliary_getmapvalue ("Events", vodeopt); // Implementation of the option 'Jacobian' has been finished, these // options can be set by the user to another value than default vradaujacfun = odepkg_auxiliary_getmapvalue ("Jacobian", vodeopt); octave_idx_type vradaujac = 0; // We need to set this if no Jac available if (!vradaujacfun.is_empty ()) vradaujac = 1; // The option JPattern will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vradaujacpat = odepkg_auxiliary_getmapvalue ("JPattern", vodeopt); if (!vradaujacpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"JPattern\" will be ignored by this solver"); // The option Vectorized will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vradauvectorize = odepkg_auxiliary_getmapvalue ("Vectorized", vodeopt); if (!vradauvectorize.is_empty ()) if (vradauvectorize.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"Vectorized\" will be ignored by this solver"); // Implementation of the option 'Mass' has been finished, these // options can be set by the user to another value than default vradaumass = odepkg_auxiliary_getmapvalue ("Mass", vodeopt); octave_idx_type vradaumas = 0; if (!vradaumass.is_empty ()) { vradaumas = 1; if (vradaumass.is_function_handle () || vradaumass.is_inline_function ()) warning_with_id ("OdePkg:InvalidOption", "Option \"Mass\" only supports constant mass matrices M() and not M(t,y)"); } // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option vradaumassstate = odepkg_auxiliary_getmapvalue ("MStateDependence", vodeopt); if (!vradaumassstate.is_empty ()) if (vradaumassstate.string_value ().compare ("weak") != 0) // 'weak' is default warning_with_id ("OdePkg:InvalidOption", "Option \"MStateDependence\" will be ignored by this solver"); // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmvpat = odepkg_auxiliary_getmapvalue ("MvPattern", vodeopt); if (!vmvpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MvPattern\" will be ignored by this solver"); // The option MassSingular will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmsing = odepkg_auxiliary_getmapvalue ("MassSingular", vodeopt); if (!vmsing.is_empty ()) if (vmsing.string_value ().compare ("maybe") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MassSingular\" will be ignored by this solver"); // The option InitialSlope will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vinitslope = odepkg_auxiliary_getmapvalue ("InitialSlope", vodeopt); if (!vinitslope.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialSlope\" will be ignored by this solver"); // The option MaxOrder will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vmaxder = odepkg_auxiliary_getmapvalue ("MaxOrder", vodeopt); if (!vmaxder.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" will be ignored by this solver"); // The option BDF will be ignored by this solver, the core Fortran // solver doesn't support this option octave_value vbdf = odepkg_auxiliary_getmapvalue ("BDF", vodeopt); if (!vbdf.is_empty ()) if (vbdf.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"BDF\" will be ignored by this solver"); // The option NewtonTol and MaxNewtonIterations will be ignored by // this solver, IT NEEDS TO BE CHECKED IF THE FORTRAN CORE SOLVER // CAN HANDLE THESE OPTIONS octave_value vntol = odepkg_auxiliary_getmapvalue ("NewtonTol", vodeopt); if (!vntol.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NewtonTol\" will be ignored by this solver"); octave_value vmaxnewton = odepkg_auxiliary_getmapvalue ("MaxNewtonIterations", vodeopt); if (!vmaxnewton.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" will be ignored by this solver"); /* Start MAINPROCESSING, set up all variables that are needed by this * solver and then initialize the solver function and get into the * main integration loop ********************************************************************/ NDArray vY0 = args(2).array_value (); NDArray vRTOL = vreltol.array_value (); NDArray vATOL = vabstol.array_value (); octave_idx_type N = args(2).length (); double X = args(1).vector_value ()(0); double* Y = vY0.fortran_vec (); double XEND = args(1).vector_value ()(1); double H = vinitstep.double_value (); double *RTOL = vRTOL.fortran_vec (); double *ATOL = vATOL.fortran_vec (); octave_idx_type ITOL = vitol; octave_idx_type IJAC = vradaujac; octave_idx_type MLJAC=N; octave_idx_type MUJAC=N; octave_idx_type IMAS=vradaumas; octave_idx_type MLMAS=N; octave_idx_type MUMAS=N; octave_idx_type IOUT = 1; // The SOLOUT function will always be called octave_idx_type LWORK = N*(N+N+7*N+3*7+3)+20; OCTAVE_LOCAL_BUFFER (double, WORK, LWORK); for (octave_idx_type vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; octave_idx_type LIWORK = (2+(7-1)/2)*N+20; OCTAVE_LOCAL_BUFFER (octave_idx_type, IWORK, LIWORK); for (octave_idx_type vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; double RPAR[1] = {0.0}; octave_idx_type IPAR[1] = {0}; octave_idx_type IDID = 0; IWORK[0] = 1; // Switch for transformation of Jacobian into Hessenberg form WORK[2] = -1; // Recompute Jacobian after every succesful step WORK[6] = vmaxstep.double_value (); // Set the maximum step size // Check if the user has set some of the options "OutputFcn", "Events" // etc. and initialize the plot, events and the solstore functions octave_value vtim = args(1).vector_value ()(0); octave_value vsol = args(2); odepkg_auxiliary_solstore (vtim, vsol, 0); if (!vradaupltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vradaupltfun, vradauoutsel, args(1), args(2), vradauextarg, 0); if (!vradauevefun.is_empty ()) odepkg_auxiliary_evaleventfun (vradauevefun, vtim, args(2), vradauextarg, 0); // We are calling the core solver and solve the set of ODEs or DAEs F77_XFCN (radau, RADAU, // Keep 5 arguments per line here (N, odepkg_radau_usrfcn, X, Y, XEND, H, RTOL, ATOL, ITOL, odepkg_radau_jacfcn, IJAC, MLJAC, MUJAC, odepkg_radau_massfcn, IMAS, MLMAS, MUMAS, odepkg_radau_solfcn, IOUT, WORK, LWORK, IWORK, LIWORK, RPAR, IPAR, IDID)); if (IDID < 0) { // odepkg_auxiliary_mebdfanalysis (IDID); error_with_id ("hugh:hugh", "missing implementation"); vretval(0) = 0.0; return (vretval); } /* Start POSTPROCESSING, check how many arguments should be returned * to the caller and check which extra arguments have to be set *******************************************************************/ // Return the results that have been stored in the // odepkg_auxiliary_solstore function octave_value vtres, vyres; odepkg_auxiliary_solstore (vtres, vyres, 2); // Set up variables to make it possible to call the cleanup // functions of 'OutputFcn' and 'Events' if any Matrix vlastline; vlastline = vyres.matrix_value (); vlastline = vlastline.extract (vlastline.rows () - 1, 0, vlastline.rows () - 1, vlastline.cols () - 1); octave_value vted = octave_value (XEND); octave_value vfin = octave_value (vlastline); if (!vradaupltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vradaupltfun, vradauoutsel, vted, vfin, vradauextarg, 2); if (!vradauevefun.is_empty ()) odepkg_auxiliary_evaleventfun (vradauevefun, vted, vfin, vradauextarg, 2); // Get the stats information as an Octave_map if the option 'Stats' // has been set with odeset // "nsteps", "nfailed", "nfevals", "npds", "ndecomps", "nlinsols" octave_value_list vstatinput; vstatinput(0) = IWORK[16]; vstatinput(1) = IWORK[17]; vstatinput(2) = IWORK[13]; vstatinput(3) = IWORK[14]; vstatinput(4) = IWORK[18]; vstatinput(5) = IWORK[19]; octave_value vstatinfo; if ((vstats.string_value ().compare ("on") == 0) && (nargout == 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, false); else if ((vstats.string_value ().compare ("on") == 0) && (nargout != 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, true); // Set up output arguments that depend on how many output arguments // are desired from the caller if (nargout == 1) { Octave_map vretmap; vretmap.assign ("x", vtres); vretmap.assign ("y", vyres); vretmap.assign ("solver", "ode2r"); if (!vstatinfo.is_empty ()) // Event implementation vretmap.assign ("stats", vstatinfo); if (!vradauevefun.is_empty ()) { vretmap.assign ("ie", vradauevesol(0).cell_value ()(1)); vretmap.assign ("xe", vradauevesol(0).cell_value ()(2)); vretmap.assign ("ye", vradauevesol(0).cell_value ()(3)); } vretval(0) = octave_value (vretmap); } else if (nargout == 2) { vretval(0) = vtres; vretval(1) = vyres; } else if (nargout == 5) { Matrix vempty; // prepare an empty matrix vretval(0) = vtres; vretval(1) = vyres; vretval(2) = vempty; vretval(3) = vempty; vretval(4) = vempty; if (!vradauevefun.is_empty ()) { vretval(2) = vradauevesol(0).cell_value ()(2); vretval(3) = vradauevesol(0).cell_value ()(3); vretval(4) = vradauevesol(0).cell_value ()(1); } } return (vretval); } /* %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference solut %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (size (vt) != [2, 1] && size (vt) != [1, 2]) %! error ('"fout" step "init"'); %! end %! elseif (isempty (vflag)) %! if (size (vt) ~= [1, 1]) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (size (vt) ~= [1, 1]) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = ode2r (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = ode2r (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = ode2r (@fpol, [0 25], 1); %!error %# fixed step sizes not supported %! B = ode2r (@fpol, [0:0.1:2], [2 0]); %!test %# one output argument %! vsol = ode2r (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode2r'); %!test %# two output arguments %! [vt, vy] = ode2r (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode2r (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = ode2r (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = ode2r (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode2r (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode2r (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode2r (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode2r (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode2r (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode2r (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %! warning ('on', 'OdePkg:HideWarning'); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set NewtonTol option to something else than default %! vopt = odeset ('NewtonTol', 1e-3); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set MaxNewtonIterations option to something else than default %! vopt = odeset ('MaxNewtonIterations', 2); %! vsol = ode2r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! warning ('on', 'OdePkg:InvalidOption'); */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_octsolver_radau5.cc0000644000176000010400000011561011711232766021130 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ /* Compile this file manually and run some tests with the following command bash:~$ mkoctfile -v -Wall -W -Wshadow odepkg_octsolver_radau5.cc \ odepkg_auxiliary_functions.cc hairer/radau5.f hairer/dc_decsol.f \ hairer/decsol.f -o ode5r.oct octave> octave --quiet --eval "autoload ('ode5r', [pwd, '/ode5r.oct']); \ test 'odepkg_octsolver_radau5.cc'" For an explanation about various parts of this source file cf. the source file odepkg_octsolver_rodas.cc. The implementation of that file is very similiar to the implementation of this file. */ #include #include #include #include #include #include "odepkg_auxiliary_functions.h" typedef octave_idx_type (*odepkg_radau5_usrtype) (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_radau5_jactype) (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_radau5_masstype) (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_radau5_soltype) (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* CONT, const octave_idx_type* LRC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN); extern "C" { F77_RET_T F77_FUNC (radau5, RADAU5) (const octave_idx_type& N, odepkg_radau5_usrtype, const double& X, const double* Y, const double& XEND, const double& H, const double* RTOL, const double* ATOL, const octave_idx_type& ITOL, odepkg_radau5_jactype, const octave_idx_type& IJAC, const octave_idx_type& MLJAC, const octave_idx_type& MUJAC, odepkg_radau5_masstype, const octave_idx_type& IMAS, const octave_idx_type& MLMAS, const octave_idx_type& MUMAS, odepkg_radau5_soltype, const octave_idx_type& IOUT, const double* WORK, const octave_idx_type& LWORK, const octave_idx_type* IWORK, const octave_idx_type& LIWORK, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, const octave_idx_type& IDID); double F77_FUNC (contr5, CONTR5) (const octave_idx_type& I, const double& S, const double* CONT, const octave_idx_type* LRC); } // extern "C" static octave_value_list vradau5extarg; static octave_value vradau5odefun; static octave_value vradau5jacfun; static octave_value vradau5evefun; static octave_value_list vradau5evesol; static octave_value vradau5pltfun; static octave_value vradau5outsel; static octave_value vradau5refine; static octave_value vradau5mass; static octave_value vradau5massstate; octave_idx_type odepkg_radau5_usrfcn (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element wise, // otherwise Octave will crash if these variables will be freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { A(vcnt) = Y[vcnt]; // octave_stdout << "I am here Y[" << vcnt << "] " << Y[vcnt] << std::endl; // octave_stdout << "I am here T " << X << std::endl; } // Fill the variable for the input arguments before evaluating the // function that keeps the set of differential algebraic equations octave_value_list varin; varin(0) = X; varin(1) = A; for (octave_idx_type vcnt = 0; vcnt < vradau5extarg.length (); vcnt++) varin(vcnt+2) = vradau5extarg(vcnt); octave_value_list vout = feval (vradau5odefun.function_value (), varin, 1); // Return the results from the function evaluation to the Fortran // solver, again copy them and don't just create a Fortran vector ColumnVector vcol = vout(0).column_vector_value (); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) F[vcnt] = vcol(vcnt); return (true); } octave_idx_type odepkg_radau5_jacfcn (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (X); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evaljacode (vradau5jacfun, vt, vy, vradau5extarg); Matrix vdfy = vout.matrix_value (); for (octave_idx_type vcol = 0; vcol < N; vcol++) for (octave_idx_type vrow = 0; vrow < N; vrow++) DFY[vrow+vcol*N] = vdfy (vrow, vcol); return (true); } F77_RET_T odepkg_radau5_massfcn (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = 0.0; // warning_with_id ("OdePkg:InvalidFunctionCall", // "Radau5 can only handle M()=const Mass matrices"); // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (0.0); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evalmassode (vradau5mass, vradau5massstate, vt, vy, vradau5extarg); Matrix vam = vout.matrix_value (); for (octave_idx_type vrow = 0; vrow < N; vrow++) for (octave_idx_type vcol = 0; vcol < N; vcol++) AM[vrow+vcol*N] = vam (vrow, vcol); return (true); } octave_idx_type odepkg_radau5_solfcn (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* CONT, const octave_idx_type* LRC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Output function, the solstore function or the Events function octave_value vt = octave_value (X); octave_value vy = octave_value (A); // Check if an 'Events' function has been set by the user if (!vradau5evefun.is_empty ()) { vradau5evesol = odepkg_auxiliary_evaleventfun (vradau5evefun, vt, vy, vradau5extarg, 1); if (!vradau5evesol(0).cell_value ()(0).is_empty ()) if (vradau5evesol(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = vradau5evesol(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = vradau5evesol(0).cell_value ()(3).matrix_value (); vt = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vy = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); IRTRN = (vradau5evesol(0).cell_value ()(0).int_value () ? -1 : 0); } } // Save the solutions that come from the Fortran core solver if this // is not the initial first call to this function if (NR > 1) odepkg_auxiliary_solstore (vt, vy, 1); // Check if an 'OutputFcn' has been set by the user (including the // values of the options for 'OutputSel' and 'Refine') if (!vradau5pltfun.is_empty ()) { if (vradau5refine.int_value () > 0) { ColumnVector B(N); double vtb = 0.0; for (octave_idx_type vcnt = 1; vcnt < vradau5refine.int_value (); vcnt++) { // Calculate time stamps between XOLD and X and get the // results at these time stamps vtb = (X - XOLD) * vcnt / vradau5refine.int_value () + XOLD; for (octave_idx_type vcou = 0; vcou < N; vcou++) B(vcou) = F77_FUNC (contr5, CONTR5) (vcou+1, vtb, CONT, LRC); // Evaluate the 'OutputFcn' with the approximated values from // the F77_FUNC before the output of the results is done octave_value vyr = octave_value (B); octave_value vtr = octave_value (vtb); odepkg_auxiliary_evalplotfun (vradau5pltfun, vradau5outsel, vtr, vyr, vradau5extarg, 1); } } // Evaluate the 'OutputFcn' with the results from the solver, if // the OutputFcn returns true then set a negative value in IRTRN IRTRN = - odepkg_auxiliary_evalplotfun (vradau5pltfun, vradau5outsel, vt, vy, vradau5extarg, 1); } return (true); } // PKG_ADD: autoload ("ode5r", "dldsolver.oct"); DEFUN_DLD (ode5r, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Command} {[@var{}] =} ode5r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{sol}] =} ode5r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode5r (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ \n\ This function file can be used to solve a set of stiff ordinary differential equations (ODEs) and stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{radau5.f}.\n\ \n\ If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}.\n\ \n\ If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}.\n\ \n\ If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector.\n\ \n\ For example,\n\ @example\n\ function y = odepkg_equations_lorenz (t, x)\n\ y = [10 * (x(2) - x(1));\n\ x(1) * (28 - x(3));\n\ x(1) * x(2) - 8/3 * x(3)];\n\ endfunction\n\ \n\ vopt = odeset (\"InitialStep\", 1e-3, \"MaxStep\", 1e-1, \\\n\ \"OutputFcn\", @@odephas3, \"Refine\", 5);\n\ ode5r (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt);\n\ @end example\n\ @end deftypefn\n\ \n\ @seealso{odepkg}") { octave_idx_type nargin = args.length (); // The number of input arguments octave_value_list vretval; // The cell array of return args Octave_map vodeopt; // The OdePkg options structure // Check number and types of all input arguments if (nargin < 3) { print_usage (); return (vretval); } // If args(0)==function_handle is valid then set the vradau5odefun // variable that has been defined "static" before if (!args(0).is_function_handle () && !args(0).is_inline_function ()) { error_with_id ("OdePkg:InvalidArgument", "First input argument must be a valid function handle"); return (vretval); } else // We store the args(0) argument in the static variable vradau5odefun vradau5odefun = args(0); // Check if the second input argument is a valid vector describing // the time window that should be solved, it may be of length 2 ONLY if (args(1).is_scalar_type () || !odepkg_auxiliary_isvector (args(1))) { error_with_id ("OdePkg:InvalidArgument", "Second input argument must be a valid vector"); return (vretval); } // Check if the thirt input argument is a valid vector describing // the initial values of the variables of the differential equations if (!odepkg_auxiliary_isvector (args(2))) { error_with_id ("OdePkg:InvalidArgument", "Third input argument must be a valid vector"); return (vretval); } // Check if there are further input arguments ie. the options // structure and/or arguments that need to be passed to the // OutputFcn, Events and/or Jacobian etc. if (nargin >= 4) { // Fourth input argument != OdePkg option, need a default structure if (!args(3).is_map ()) { octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure for (octave_idx_type vcnt = 3; vcnt < nargin; vcnt++) vradau5extarg(vcnt-3) = args(vcnt); // Save arguments in vradau5extarg } // Fourth input argument == OdePkg option, extra input args given too else if (nargin > 4) { octave_value_list varin; varin(0) = args(3); varin(1) = "ode5r"; octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create structure from args(4) for (octave_idx_type vcnt = 4; vcnt < nargin; vcnt++) vradau5extarg(vcnt-4) = args(vcnt); // Save extra arguments } // Fourth input argument == OdePkg option, no extra input args given else { octave_value_list varin; varin(0) = args(3); varin(1) = "ode5r"; // Check structure octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create a default structure } } // if (nargin >= 4) else { // if nargin == 3, everything else has been checked before octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure } /* Start PREPROCESSING, ie. check which options have been set and * print warnings if there are options that can't be handled by this * solver or have not been implemented yet *******************************************************************/ // Implementation of the option RelTol has been finished, this // option can be set by the user to another value than default value octave_value vreltol = odepkg_auxiliary_getmapvalue ("RelTol", vodeopt); if (vreltol.is_empty ()) { vreltol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"RelTol\" not set, new value %3.1e is used", vreltol.double_value ()); } // vreltol.print (octave_stdout, true); return (vretval); if (!vreltol.is_scalar_type ()) { if (vreltol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"RelTol\" must be the same as the number of equations"); return (vretval); } } // Implementation of the option AbsTol has been finished, this // option can be set by the user to another value than default value octave_value vabstol = odepkg_auxiliary_getmapvalue ("AbsTol", vodeopt); if (vabstol.is_empty ()) { vabstol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"AbsTol\" not set, new value %3.1e is used", vabstol.double_value ()); } // vabstol.print (octave_stdout, true); return (vretval); if (!vabstol.is_scalar_type ()) { if (vabstol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"AbsTol\" must be the same as the number of equations"); return (vretval); } } // Setting the tolerance type that depends on the types (scalar or // vector) of the options RelTol and AbsTol octave_idx_type vitol = 0; if (vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 0; else if (!vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 1; else { error_with_id ("OdePkg:InvalidOption", "Values of \"RelTol\" and \"AbsTol\" must have same length"); return (vretval); } // The option NormControl will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnorm = odepkg_auxiliary_getmapvalue ("NormControl", vodeopt); if (!vnorm.is_empty ()) if (vnorm.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"NormControl\" will be ignored by this solver"); // The option NonNegative will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnneg = odepkg_auxiliary_getmapvalue ("NonNegative", vodeopt); if (!vnneg.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NonNegative\" will be ignored by this solver"); // Implementation of the option OutputFcn has been finished, this // option can be set by the user to another value than default value vradau5pltfun = odepkg_auxiliary_getmapvalue ("OutputFcn", vodeopt); if (vradau5pltfun.is_empty () && nargout == 0) vradau5pltfun = "odeplot"; // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vradau5outsel = odepkg_auxiliary_getmapvalue ("OutputSel", vodeopt); // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vradau5refine = odepkg_auxiliary_getmapvalue ("Refine", vodeopt); // Implementation of the option Stats has been finished, this option // can be set by the user to another value than default value octave_value vstats = odepkg_auxiliary_getmapvalue ("Stats", vodeopt); // Implementation of the option InitialStep has been finished, this // option can be set by the user to another value than default value octave_value vinitstep = odepkg_auxiliary_getmapvalue ("InitialStep", vodeopt); if (args(1).length () > 2) { error_with_id ("OdePkg:InvalidOption", "Fixed time stamps are not supported by this solver"); } if (vinitstep.is_empty ()) { vinitstep = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" not set, new value %3.1e is used", vinitstep.double_value ()); } // Implementation of the option MaxStep has been finished, this // option can be set by the user to another value than default value octave_value vmaxstep = odepkg_auxiliary_getmapvalue ("MaxStep", vodeopt); if (vmaxstep.is_empty () && args(1).length () == 2) { vmaxstep = (args(1).vector_value ()(1) - args(1).vector_value ()(0)) / 12.5; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxStep\" not set, new value %3.1e is used", vmaxstep.double_value ()); } // Implementation of the option Events has been finished, this // option can be set by the user to another value than default // value, odepkg_structure_check already checks for a valid value vradau5evefun = odepkg_auxiliary_getmapvalue ("Events", vodeopt); // Implementation of the option 'Jacobian' has been finished, these // options can be set by the user to another value than default vradau5jacfun = odepkg_auxiliary_getmapvalue ("Jacobian", vodeopt); octave_idx_type vradau5jac = 0; // We need to set this if no Jac available if (!vradau5jacfun.is_empty ()) vradau5jac = 1; // The option JPattern will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vradau5jacpat = odepkg_auxiliary_getmapvalue ("JPattern", vodeopt); if (!vradau5jacpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"JPattern\" will be ignored by this solver"); // The option Vectorized will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vradau5vectorize = odepkg_auxiliary_getmapvalue ("Vectorized", vodeopt); if (!vradau5vectorize.is_empty ()) if (vradau5vectorize.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"Vectorized\" will be ignored by this solver"); // Implementation of the option 'Mass' has been finished, these // options can be set by the user to another value than default vradau5mass = odepkg_auxiliary_getmapvalue ("Mass", vodeopt); octave_idx_type vradau5mas = 0; if (!vradau5mass.is_empty ()) { vradau5mas = 1; if (vradau5mass.is_function_handle () || vradau5mass.is_inline_function ()) warning_with_id ("OdePkg:InvalidOption", "Option \"Mass\" only supports constant mass matrices M() and not M(t,y)"); } // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option vradau5massstate = odepkg_auxiliary_getmapvalue ("MStateDependence", vodeopt); if (!vradau5massstate.is_empty ()) if (vradau5massstate.string_value ().compare ("weak") != 0) // 'weak' is default warning_with_id ("OdePkg:InvalidOption", "Option \"MStateDependence\" will be ignored by this solver"); // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmvpat = odepkg_auxiliary_getmapvalue ("MvPattern", vodeopt); if (!vmvpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MvPattern\" will be ignored by this solver"); // The option MassSingular will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmsing = odepkg_auxiliary_getmapvalue ("MassSingular", vodeopt); if (!vmsing.is_empty ()) if (vmsing.string_value ().compare ("maybe") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MassSingular\" will be ignored by this solver"); // The option InitialSlope will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vinitslope = odepkg_auxiliary_getmapvalue ("InitialSlope", vodeopt); if (!vinitslope.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialSlope\" will be ignored by this solver"); // The option MaxOrder will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vmaxder = odepkg_auxiliary_getmapvalue ("MaxOrder", vodeopt); if (!vmaxder.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" will be ignored by this solver"); // The option BDF will be ignored by this solver, the core Fortran // solver doesn't support this option octave_value vbdf = odepkg_auxiliary_getmapvalue ("BDF", vodeopt); if (!vbdf.is_empty ()) if (vbdf.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"BDF\" will be ignored by this solver"); // Implementation of the option NewtonTol has been finished, this // option can be set by the user to another value than default value octave_value vNTOL = odepkg_auxiliary_getmapvalue ("NewtonTol", vodeopt); if (vNTOL.is_empty ()) { vNTOL = 0; warning_with_id ("OdePkg:InvalidOption", "Option \"NewtonTol\" not set, default value is used"); } // Implementation of the option MaxNewtonIterations has been finished, this // option can be set by the user to another value than default value octave_value vmaxnit = odepkg_auxiliary_getmapvalue ("MaxNewtonIterations", vodeopt); if (vmaxnit.is_empty ()) { vmaxnit = 7; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" not set, default value 7 is used"); } else if (vmaxnit.int_value () < 1) { vmaxnit = 7; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" is zero, default value 7 is used"); } /* Start MAINPROCESSING, set up all variables that are needed by this * solver and then initialize the solver function and get into the * main integration loop ********************************************************************/ NDArray vY0 = args(2).array_value (); NDArray vRTOL = vreltol.array_value (); NDArray vATOL = vabstol.array_value (); octave_idx_type N = args(2).length (); double X = args(1).vector_value ()(0); double* Y = vY0.fortran_vec (); double XEND = args(1).vector_value ()(1); double H = vinitstep.double_value (); double *RTOL = vRTOL.fortran_vec (); double *ATOL = vATOL.fortran_vec (); octave_idx_type ITOL = vitol; octave_idx_type IJAC = vradau5jac; octave_idx_type MLJAC=N; octave_idx_type MUJAC=N; octave_idx_type IMAS=vradau5mas; octave_idx_type MLMAS=N; octave_idx_type MUMAS=N; octave_idx_type IOUT = 1; // The SOLOUT function will always be called octave_idx_type LWORK = N*(N+N+7*N+3*7+3)+20; OCTAVE_LOCAL_BUFFER (double, WORK, LWORK); for (octave_idx_type vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; octave_idx_type LIWORK = (2+(7-1)/2)*N+20; OCTAVE_LOCAL_BUFFER (octave_idx_type, IWORK, LIWORK); for (octave_idx_type vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; double RPAR[1] = {0.0}; octave_idx_type IPAR[1] = {0}; octave_idx_type IDID = 0; IWORK[0] = 1; // Switch for transformation of Jacobian into Hessenberg form IWORK[2] = vmaxnit.int_value (); // Maximum number of Newton iterations WORK[2] = -1; // Recompute Jacobian after every succesful step WORK[3] = vNTOL.double_value (); // Tolerance of Newton iteration WORK[6] = vmaxstep.double_value (); // Set the maximum step size // Check if the user has set some of the options "OutputFcn", "Events" // etc. and initialize the plot, events and the solstore functions octave_value vtim = args(1).vector_value ()(0); octave_value vsol = args(2); odepkg_auxiliary_solstore (vtim, vsol, 0); if (!vradau5pltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vradau5pltfun, vradau5outsel, args(1), args(2), vradau5extarg, 0); if (!vradau5evefun.is_empty ()) odepkg_auxiliary_evaleventfun (vradau5evefun, vtim, args(2), vradau5extarg, 0); // octave_stdout << "X VALUE=" << X << XEND << std::endl; // We are calling the core solver and solve the set of ODEs or DAEs F77_XFCN (radau5, RADAU5, // Keep 5 arguments per line here (N, odepkg_radau5_usrfcn, X, Y, XEND, H, RTOL, ATOL, ITOL, odepkg_radau5_jacfcn, IJAC, MLJAC, MUJAC, odepkg_radau5_massfcn, IMAS, MLMAS, MUMAS, odepkg_radau5_solfcn, IOUT, WORK, LWORK, IWORK, LIWORK, RPAR, IPAR, IDID)); if (IDID < 0) { // odepkg_auxiliary_mebdfanalysis (IDID); error_with_id ("hugh:hugh", "missing implementation"); vretval(0) = 0.0; return (vretval); } /* Start POSTPROCESSING, check how many arguments should be returned * to the caller and check which extra arguments have to be set *******************************************************************/ // Return the results that have been stored in the // odepkg_auxiliary_solstore function octave_value vtres, vyres; odepkg_auxiliary_solstore (vtres, vyres, 2); // Set up variables to make it possible to call the cleanup // functions of 'OutputFcn' and 'Events' if any Matrix vlastline; vlastline = vyres.matrix_value (); vlastline = vlastline.extract (vlastline.rows () - 1, 0, vlastline.rows () - 1, vlastline.cols () - 1); octave_value vted = octave_value (XEND); octave_value vfin = octave_value (vlastline); if (!vradau5pltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vradau5pltfun, vradau5outsel, vted, vfin, vradau5extarg, 2); if (!vradau5evefun.is_empty ()) odepkg_auxiliary_evaleventfun (vradau5evefun, vted, vfin, vradau5extarg, 2); // Get the stats information as an Octave_map if the option 'Stats' // has been set with odeset // "nsteps", "nfailed", "nfevals", "npds", "ndecomps", "nlinsols" octave_value_list vstatinput; vstatinput(0) = IWORK[16]; vstatinput(1) = IWORK[17]; vstatinput(2) = IWORK[13]; vstatinput(3) = IWORK[14]; vstatinput(4) = IWORK[18]; vstatinput(5) = IWORK[19]; octave_value vstatinfo; if ((vstats.string_value ().compare ("on") == 0) && (nargout == 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, false); else if ((vstats.string_value ().compare ("on") == 0) && (nargout != 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, true); // Set up output arguments that depend on how many output arguments // are desired from the caller if (nargout == 1) { Octave_map vretmap; vretmap.assign ("x", vtres); vretmap.assign ("y", vyres); vretmap.assign ("solver", "ode5r"); if (!vstatinfo.is_empty ()) // Event implementation vretmap.assign ("stats", vstatinfo); if (!vradau5evefun.is_empty ()) { vretmap.assign ("ie", vradau5evesol(0).cell_value ()(1)); vretmap.assign ("xe", vradau5evesol(0).cell_value ()(2)); vretmap.assign ("ye", vradau5evesol(0).cell_value ()(3)); } vretval(0) = octave_value (vretmap); } else if (nargout == 2) { vretval(0) = vtres; vretval(1) = vyres; } else if (nargout == 5) { Matrix vempty; // prepare an empty matrix vretval(0) = vtres; vretval(1) = vyres; vretval(2) = vempty; vretval(3) = vempty; vretval(4) = vempty; if (!vradau5evefun.is_empty ()) { vretval(2) = vradau5evesol(0).cell_value ()(2); vretval(3) = vradau5evesol(0).cell_value ()(3); vretval(4) = vradau5evesol(0).cell_value ()(1); } } return (vretval); } /* %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference solut %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (size (vt) != [2, 1] && size (vt) != [1, 2]) %! error ('"fout" step "init"'); %! end %! elseif (isempty (vflag)) %! if (size (vt) ~= [1, 1]) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (size (vt) ~= [1, 1]) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = ode5r (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = ode5r (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = ode5r (@flor, [0 25], 1); %!error %# fixed step sizes not supported %! B = ode5r (@fpol, [0:0.1:2], [2 0]); %!test %# one output argument %! vsol = ode5r (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'ode5r'); %!test %# two output arguments %! [vt, vy] = ode5r (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = ode5r (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = ode5r (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = ode5r (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = ode5r (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = ode5r (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = ode5r (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = ode5r (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = ode5r (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = ode5r (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %! warning ('on', 'OdePkg:HideWarning'); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set NewtonTol option to something else than default %! vopt = odeset ('NewtonTol', 1e-3); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set MaxNewtonIterations option to something else than default %! vopt = odeset ('MaxNewtonIterations', 2); %! vsol = ode5r (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! warning ('on', 'OdePkg:InvalidOption'); */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_octsolver_rodas.cc0000644000176000010400000014172311730535113021054 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ /* Compile this file manually and run some tests with the following command bash:~$ mkoctfile -v -Wall -W -Wshadow odepkg_octsolver_rodas.cc \ odepkg_auxiliary_functions.cc hairer/rodas.f hairer/dc_decsol.f \ hairer/decsol.f -o oders.oct octave> octave --quiet --eval "autoload ('oders', [pwd, '/oders.oct']); \ test 'odepkg_octsolver_rodas.cc'" */ #include #include #include #include #include #include "odepkg_auxiliary_functions.h" /* -*- texinfo -*- * @subsection Source File @file{odepkg_octsolver_rodas.cc} * * @deftp {Typedef} {octave_idx_type (*odepkg_rodas_usrtype)} * This @code{typedef} is used to define the input and output arguments of the user function for the DAE problem that is further needed by the Fortran core solver @code{rodas}. The implementation of this @code{typedef} is * * @example * typedef octave_idx_type (*odepkg_rodas_usrtype) * (const octave_idx_type& N, const double& X, const double* Y, * double* F, GCC_ATTR_UNUSED const double* RPAR, * GCC_ATTR_UNUSED const octave_idx_type* IPAR); * @end example * @end deftp */ typedef octave_idx_type (*odepkg_rodas_usrtype) (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); /* -*- texinfo -*- * @deftp {Typedef} {octave_idx_type (*odepkg_rodas_jactype)} * * This @code{typedef} is used to define the input and output arguments of the @code{Jacobian} function for the DAE problem that is further needed by the Fortran core solver @code{rodas}. The implementation of this @code{typedef} is * * @example * typedef octave_idx_type (*odepkg_rodas_jactype) * (const octave_idx_type& N, const double& X, const double* Y, * double* DFY, GCC_ATTR_UNUSED const octave_idx_type* LDFY, * GCC_ATTR_UNUSED const double* RPAR, * GCC_ATTR_UNUSED const octave_idx_type* IPAR); * @end example * @end deftp */ typedef octave_idx_type (*odepkg_rodas_jactype) (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); /* -*- texinfo -*- * @deftp {Typedef} {octave_idx_type (*odepkg_rodas_masstype)} * * This @code{typedef} is used to define the input and output arguments of the @code{Mass} function for the DAE problem that is further needed by the Fortran core solver @code{rodas}. The implementation of this @code{typedef} is * * @example * typedef octave_idx_type (*odepkg_rodas_masstype) * (const octave_idx_type& N, double* AM, * GCC_ATTR_UNUSED const octave_idx_type* LMAS, * GCC_ATTR_UNUSED const double* RPAR, * GCC_ATTR_UNUSED const octave_idx_type* IPAR); * @end example * @end deftp */ typedef octave_idx_type (*odepkg_rodas_masstype) (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); /* -*- texinfo -*- * @deftp {Typedef} {octave_idx_type (*odepkg_rodas_soltype)} * * This @code{typedef} is used to define the input and output arguments of the @code{Solution} function for the DAE problem that is further needed by the Fortran core solver @code{rodas}. The implementation of this @code{typedef} is * * @example * typedef octave_idx_type (*odepkg_rodas_soltype) * (const octave_idx_type& NR, const double& XOLD, const double& X, * const double* Y, const double* CONT, const octave_idx_type* LRC, * const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, * GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN); * @end example * @end deftp */ typedef octave_idx_type (*odepkg_rodas_soltype) (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* CONT, const octave_idx_type* LRC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN); /* -*- texinfo -*- * @deftp {Typedef} {octave_idx_type (*odepkg_rodas_dfxtype)} * * This @code{typedef} is used to define the input and output arguments of the @code{DFX} function for the DAE problem that is further needed by the Fortran core solver @code{rodas}. The implementation of this @code{typedef} is * * @example * typedef octave_idx_type (*odepkg_rodas_dfxtype) * (GCC_ATTR_UNUSED const octave_idx_type& N, * GCC_ATTR_UNUSED const double& X, * GCC_ATTR_UNUSED const double* Y, * GCC_ATTR_UNUSED const double* FX, * GCC_ATTR_UNUSED const double* RPAR, * GCC_ATTR_UNUSED const octave_idx_type* IPAR); * @end example * @end deftp */ typedef octave_idx_type (*odepkg_rodas_dfxtype) (GCC_ATTR_UNUSED const octave_idx_type& N, GCC_ATTR_UNUSED const double& X, GCC_ATTR_UNUSED const double* Y, GCC_ATTR_UNUSED const double* FX, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); extern "C" { /* -*- texinfo -*- * @deftp {Prototype} {F77_RET_T F77_FUNC (rodas, RODAS)} (const octave_idx_type& N, odepkg_rodas_usrtype, const octave_idx_type& IFCN, const octave_idx_type& X, const double* Y, const double& XEND, const double& H, const double* RTOL, const double* ATOL, const octave_idx_type& ITOL, odepkg_rodas_jactype, const octave_idx_type& IJAC, const octave_idx_type& MLJAC, const octave_idx_type& MUJAC, odepkg_rodas_dfxtype, const octave_idx_type& IDFX, odepkg_rodas_masstype, const octave_idx_type& IMAS, const octave_idx_type& MLMAS, const octave_idx_type& MUMAS, odepkg_rodas_soltype, const octave_idx_type& IOUT, const double* WORK, const octave_idx_type& LWORK, const octave_idx_type* IWORK, const octave_idx_type& LIWORK, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, const octave_idx_type& IDID); * * The prototype @code{F77_FUNC (rodas, RODAS)} is used to represent the information about the Fortran core solver @code{rodas} that is defined in the Fortran source file @file{rodas.f} (cf. the Fortran source file @file{rodas.f} for further details). * @end deftp */ F77_RET_T F77_FUNC (rodas, RODAS) (const octave_idx_type& N, odepkg_rodas_usrtype, const octave_idx_type& IFCN, const double& X, const double* Y, const double& XEND, const double& H, const double* RTOL, const double* ATOL, const octave_idx_type& ITOL, odepkg_rodas_jactype, const octave_idx_type& IJAC, const octave_idx_type& MLJAC, const octave_idx_type& MUJAC, odepkg_rodas_dfxtype, const octave_idx_type& IDFX, odepkg_rodas_masstype, const octave_idx_type& IMAS, const octave_idx_type& MLMAS, const octave_idx_type& MUMAS, odepkg_rodas_soltype, const octave_idx_type& IOUT, const double* WORK, const octave_idx_type& LWORK, const octave_idx_type* IWORK, const octave_idx_type& LIWORK, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, const octave_idx_type& IDID); /* -*- texinfo -*- * @deftp {Prototype} {double F77_FUNC (contro, CONTRO)} (const octave_idx_type& I, const double* S, const double* CONT, const octave_idx_type* LRC); * * The prototype @code{F77_FUNC (contro, CONTRO)} is used to represent the information about a continous output calculation for the @code{rodas} algorithm that is defined in the Fortran source file @file{rodas.f} (cf. the Fortran source file @file{rodas.f} for further details). * @end deftp */ double F77_FUNC (contro, CONTRO) (const octave_idx_type& I, const double& S, const double* CONT, const octave_idx_type* LRC); /* -*- texinfo -*- * @deftp {Prototype} {F77_RET_T F77_FUNC (dfx, DFX)} (GCC_ATTR_UNUSED const octave_idx_type& N, GCC_ATTR_UNUSED const double& X, GCC_ATTR_UNUSED const double* Y, GCC_ATTR_UNUSED const double* FX, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); * * The prototype @code{F77_RET_T F77_FUNC (dfx, DFX)} is used to represent the information about a DFX dummy function (that will never be called because it is not supported) for the @code{rodas} algorithm that is defined in the Fortran source file @file{rodas.f} (cf. the Fortran source file @file{rodas.f} for further details). * @end deftp */ F77_RET_T F77_FUNC (dfx, DFX) (GCC_ATTR_UNUSED const octave_idx_type& N, GCC_ATTR_UNUSED const double& X, GCC_ATTR_UNUSED const double* Y, GCC_ATTR_UNUSED const double* FX, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); } // extern "C" /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value_list} {vrodasextarg} * * This static variable is used to store the extra arguments that are needed by some or by all of the @code{OutputFcn}, the @code{Jacobian} function, the @code{Mass} function and the @code{Events} function while solving the DAE problem. * @end deftypevr */ static octave_value_list vrodasextarg; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasodefun} * * This static variable is used to store the value for the user function that defines the set of DAEs. * @end deftypevr */ static octave_value vrodasodefun; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasjacfun} * * This static variable is used to store the value for the @code{Jacobian} function that may be needed from the Fortran core solver while solving. * @end deftypevr */ static octave_value vrodasjacfun; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasevefun} * * This static variable is used to store the value for the @code{Events} function that may be needed from the Fortran core solver while solving. * @end deftypevr */ static octave_value vrodasevefun; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasevesol} * * This static variable is used to store the results that come from the @code{Events} function while solving. * @end deftypevr */ static octave_value_list vrodasevesol; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodaspltfun} * * This static variable is used to store the value for the @code{OutputFcn} function if any. * @end deftypevr */ static octave_value vrodaspltfun; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasoutsel} * * This static variable is used to store the value for the @code{OutputSel} vector if any. * @end deftypevr */ static octave_value vrodasoutsel; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasrefine} * * This static variable is used to store the value for the @code{Refine} option if any. * @end deftypevr */ static octave_value vrodasrefine; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasmass} * * This static variable is used to store the value for the @code{Mass} function while solving. * @end deftypevr */ static octave_value vrodasmass; /* -*- texinfo -*- * @deftypevr {Variable} {static octave_value} {vrodasmassstate} * * This static variable is used to store the value for the @code{MStateDependence} string if any. * @end deftypevr */ static octave_value vrodasmassstate; /* -*- texinfo -*- * @deftypefn {Function} {octave_idx_type} {odepkg_rodas_usrfcn} (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) * * Return @code{true} if the evaluation of the user type function (that is defined for a special DAE problem in Octave) was successful, otherwise return @code{false}. This function is directly called from the Fortran core solver @code{rodas}. The input arguments of this function are * * @itemize @minus * @item @var{N}: The number of equations that are defined for the DAE--problem * @item @var{X}: The actual time stamp for the current function evaluation * @item @var{Y}: The function values from the last successful integration step of length @var{N} * @item @var{F}: The solution vector that needs to be calculated of length @var{N} * @item @var{RPAR}: The real parameters that are passed to the user function (unused) * @item @var{IPAR}: The integer parameters that are passed to the user function (unused) * @end itemize * @end deftypefn */ octave_idx_type odepkg_rodas_usrfcn (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element wise, // otherwise Octave will crash if these variables will be freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { A(vcnt) = Y[vcnt]; // octave_stdout << "I am here Y[" << vcnt << "] " << Y[vcnt] << std::endl; // octave_stdout << "I am here T " << X << std::endl; } // Fill the variable for the input arguments before evaluating the // function that keeps the set of differential algebraic equations octave_value_list varin; varin(0) = X; varin(1) = A; for (octave_idx_type vcnt = 0; vcnt < vrodasextarg.length (); vcnt++) varin(vcnt+2) = vrodasextarg(vcnt); octave_value_list vout = feval (vrodasodefun.function_value (), varin, 1); // Return the results from the function evaluation to the Fortran // solver, again copy them and don't just create a Fortran vector ColumnVector vcol = vout(0).column_vector_value (); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) F[vcnt] = vcol(vcnt); return (true); } /* -*- texinfo -*- * @deftypefn {Function} {octave_idx_type} {odepkg_mebdfi_jacfcn} (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) * * Return @code{true} if the evaluation of the @code{Jacobian} function (that is defined for a special DAE problem in Octave) was successful, otherwise return @code{false}. This function is directly called from the Fortran core solver @code{rodas}. The input arguments of this function are * * @itemize @minus * @item @var{N}: The number of equations that are defined for the DAE--problem * @item @var{X}: The actual time stamp for the current function evaluation * @item @var{Y}: The function values from the last successful integration step of length @var{N} * @item @var{DFY}: The values of partial derivatives of the Jacobian matrix of size @var{N} * @item @var{LDFY}: * @item @var{RPAR}: The real parameters that are passed to the user function (unused) * @item @var{IPAR}: The integer parameters that are passed to the user function (unused) * @end itemize * @end deftypefn */ octave_idx_type odepkg_rodas_jacfcn (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (X); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evaljacode (vrodasjacfun, vt, vy, vrodasextarg); Matrix vdfy = vout.matrix_value (); for (octave_idx_type vcol = 0; vcol < N; vcol++) for (octave_idx_type vrow = 0; vrow < N; vrow++) DFY[vrow+vcol*N] = vdfy (vrow, vcol); return (true); } /* -*- texinfo -*- * odepkg_rodas_massfcn - TODO */ F77_RET_T odepkg_rodas_massfcn (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = 0.0; // warning_with_id ("OdePkg:InvalidFunctionCall", // "Rodas can only handle M()=const Mass matrices"); // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (0.0); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evalmassode (vrodasmass, vrodasmassstate, vt, vy, vrodasextarg); Matrix vam = vout.matrix_value (); for (octave_idx_type vrow = 0; vrow < N; vrow++) for (octave_idx_type vcol = 0; vcol < N; vcol++) AM[vrow+vcol*N] = vam (vrow, vcol); return (true); } /* -*- texinfo -*- * odepkg_rodas_solfcn - TODO */ octave_idx_type odepkg_rodas_solfcn (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* CONT, const octave_idx_type* LRC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Output function, the solstore function or the Events function octave_value vt = octave_value (X); octave_value vy = octave_value (A); // Check if an 'Events' function has been set by the user if (!vrodasevefun.is_empty ()) { vrodasevesol = odepkg_auxiliary_evaleventfun (vrodasevefun, vt, vy, vrodasextarg, 1); if (!vrodasevesol(0).cell_value ()(0).is_empty ()) if (vrodasevesol(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = vrodasevesol(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = vrodasevesol(0).cell_value ()(3).matrix_value (); vt = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vy = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); IRTRN = (vrodasevesol(0).cell_value ()(0).int_value () ? -1 : 0); } } // Save the solutions that come from the Fortran core solver if this // is not the initial first call to this function if (NR > 1) odepkg_auxiliary_solstore (vt, vy, 1); // Check if an 'OutputFcn' has been set by the user (including the // values of the options for 'OutputSel' and 'Refine') if (!vrodaspltfun.is_empty ()) { if (vrodasrefine.int_value () > 0) { ColumnVector B(N); double vtb = 0.0; for (octave_idx_type vcnt = 1; vcnt < vrodasrefine.int_value (); vcnt++) { // Calculate time stamps between XOLD and X and get the // results at these time stamps vtb = (X - XOLD) * vcnt / vrodasrefine.int_value () + XOLD; for (octave_idx_type vcou = 0; vcou < N; vcou++) B(vcou) = F77_FUNC (contro, CONTRO) (vcou+1, vtb, CONT, LRC); // Evaluate the 'OutputFcn' with the approximated values from // the F77_FUNC before the output of the results is done octave_value vyr = octave_value (B); octave_value vtr = octave_value (vtb); odepkg_auxiliary_evalplotfun (vrodaspltfun, vrodasoutsel, vtr, vyr, vrodasextarg, 1); } } // Evaluate the 'OutputFcn' with the results from the solver, if // the OutputFcn returns true then set a negative value in IRTRN IRTRN = - odepkg_auxiliary_evalplotfun (vrodaspltfun, vrodasoutsel, vt, vy, vrodasextarg, 1); } return (true); } /* -*- texinfo -*- * odepkg_rodas_solfcn - TODO dummy function */ octave_idx_type odepkg_rodas_dfxfcn (GCC_ATTR_UNUSED const octave_idx_type& N, GCC_ATTR_UNUSED const double& X, GCC_ATTR_UNUSED const double* Y, GCC_ATTR_UNUSED const double* FX, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { warning_with_id ("OdePkg:InvalidFunctionCall", "function odepkg_rodas_dfxfcn: This warning message should never appear"); return (true); } // PKG_ADD: autoload ("oders", "dldsolver.oct"); DEFUN_DLD (oders, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{}] =} oders (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{sol}] =} oders (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} oders (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ \n\ This function file can be used to solve a set of stiff ordinary differential equations (ODEs) and stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{rodas.f}.\n\ \n\ If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}.\n\ \n\ If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}.\n\ \n\ If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector.\n\ \n\ For example,\n\ @example\n\ function y = odepkg_equations_lorenz (t, x)\n\ y = [10 * (x(2) - x(1));\n\ x(1) * (28 - x(3));\n\ x(1) * x(2) - 8/3 * x(3)];\n\ endfunction\n\ \n\ vopt = odeset (\"InitialStep\", 1e-3, \"MaxStep\", 1e-1, \\\n\ \"OutputFcn\", @@odephas3, \"Refine\", 5);\n\ oders (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt);\n\ @end example\n\ @end deftypefn\n\ \n\ @seealso{odepkg}") { octave_idx_type nargin = args.length (); // The number of input arguments octave_value_list vretval; // The cell array of return args Octave_map vodeopt; // The OdePkg options structure // Check number and types of all input arguments if (nargin < 3) { print_usage (); return (vretval); } // If args(0)==function_handle is valid then set the vrodasodefun // variable that has been defined "static" before if (!args(0).is_function_handle () && !args(0).is_inline_function ()) { error_with_id ("OdePkg:InvalidArgument", "First input argument must be a valid function handle"); return (vretval); } else // We store the args(0) argument in the static variable vrodasodefun vrodasodefun = args(0); // Check if the second input argument is a valid vector describing // the time window that should be solved, it may be of length 2 ONLY if (args(1).is_scalar_type () || !odepkg_auxiliary_isvector (args(1))) { error_with_id ("OdePkg:InvalidArgument", "Second input argument must be a valid vector"); return (vretval); } // Check if the thirt input argument is a valid vector describing // the initial values of the variables of the differential equations if (!odepkg_auxiliary_isvector (args(2))) { error_with_id ("OdePkg:InvalidArgument", "Third input argument must be a valid vector"); return (vretval); } // Check if there are further input arguments ie. the options // structure and/or arguments that need to be passed to the // OutputFcn, Events and/or Jacobian etc. if (nargin >= 4) { // Fourth input argument != OdePkg option, need a default structure if (!args(3).is_map ()) { octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure for (octave_idx_type vcnt = 3; vcnt < nargin; vcnt++) vrodasextarg(vcnt-3) = args(vcnt); // Save arguments in vrodasextarg } // Fourth input argument == OdePkg option, extra input args given too else if (nargin > 4) { octave_value_list varin; varin(0) = args(3); varin(1) = "oders"; octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create structure from args(4) for (octave_idx_type vcnt = 4; vcnt < nargin; vcnt++) vrodasextarg(vcnt-4) = args(vcnt); // Save extra arguments } // Fourth input argument == OdePkg option, no extra input args given else { octave_value_list varin; varin(0) = args(3); varin(1) = "oders"; // Check structure octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create a default structure } } // if (nargin >= 4) else { // if nargin == 3, everything else has been checked before octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure } /* Start PREPROCESSING, ie. check which options have been set and * print warnings if there are options that can't be handled by this * solver or have not been implemented yet *******************************************************************/ // Implementation of the option RelTol has been finished, this // option can be set by the user to another value than default value octave_value vreltol = odepkg_auxiliary_getmapvalue ("RelTol", vodeopt); if (vreltol.is_empty ()) { vreltol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"RelTol\" not set, new value %3.1e is used", vreltol.double_value ()); } // vreltol.print (octave_stdout, true); return (vretval); if (!vreltol.is_scalar_type ()) { if (vreltol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"RelTol\" must be the same as the number of equations"); return (vretval); } } // Implementation of the option AbsTol has been finished, this // option can be set by the user to another value than default value octave_value vabstol = odepkg_auxiliary_getmapvalue ("AbsTol", vodeopt); if (vabstol.is_empty ()) { vabstol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"AbsTol\" not set, new value %3.1e is used", vabstol.double_value ()); } // vabstol.print (octave_stdout, true); return (vretval); if (!vabstol.is_scalar_type ()) { if (vabstol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"AbsTol\" must be the same as the number of equations"); return (vretval); } } // Setting the tolerance type that depends on the types (scalar or // vector) of the options RelTol and AbsTol octave_idx_type vitol = 0; if (vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 0; else if (!vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 1; else { error_with_id ("OdePkg:InvalidOption", "Values of \"RelTol\" and \"AbsTol\" must have same length"); return (vretval); } // The option NormControl will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnorm = odepkg_auxiliary_getmapvalue ("NormControl", vodeopt); if (!vnorm.is_empty ()) if (vnorm.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"NormControl\" will be ignored by this solver"); // The option NonNegative will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnneg = odepkg_auxiliary_getmapvalue ("NonNegative", vodeopt); if (!vnneg.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NonNegative\" will be ignored by this solver"); // Implementation of the option OutputFcn has been finished, this // option can be set by the user to another value than default value vrodaspltfun = odepkg_auxiliary_getmapvalue ("OutputFcn", vodeopt); if (vrodaspltfun.is_empty () && nargout == 0) vrodaspltfun = "odeplot"; // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vrodasoutsel = odepkg_auxiliary_getmapvalue ("OutputSel", vodeopt); // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vrodasrefine = odepkg_auxiliary_getmapvalue ("Refine", vodeopt); // Implementation of the option Stats has been finished, this option // can be set by the user to another value than default value octave_value vstats = odepkg_auxiliary_getmapvalue ("Stats", vodeopt); // Implementation of the option InitialStep has been finished, this // option can be set by the user to another value than default value octave_value vinitstep = odepkg_auxiliary_getmapvalue ("InitialStep", vodeopt); if (args(1).length () > 2) { error_with_id ("OdePkg:InvalidOption", "Fixed time stamps are not supported by this solver"); } if (vinitstep.is_empty ()) { vinitstep = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" not set, new value %3.1e is used", vinitstep.double_value ()); } // Implementation of the option MaxStep has been finished, this // option can be set by the user to another value than default value octave_value vmaxstep = odepkg_auxiliary_getmapvalue ("MaxStep", vodeopt); if (vmaxstep.is_empty () && args(1).length () == 2) { vmaxstep = (args(1).vector_value ()(1) - args(1).vector_value ()(0)) / 12.5; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxStep\" not set, new value %3.1e is used", vmaxstep.double_value ()); } // Implementation of the option Events has been finished, this // option can be set by the user to another value than default // value, odepkg_structure_check already checks for a valid value vrodasevefun = odepkg_auxiliary_getmapvalue ("Events", vodeopt); // Implementation of the option 'Jacobian' has been finished, these // options can be set by the user to another value than default vrodasjacfun = odepkg_auxiliary_getmapvalue ("Jacobian", vodeopt); octave_idx_type vrodasjac = 0; // We need to set this if no Jac available if (!vrodasjacfun.is_empty ()) vrodasjac = 1; // The option JPattern will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vrodasjacpat = odepkg_auxiliary_getmapvalue ("JPattern", vodeopt); if (!vrodasjacpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"JPattern\" will be ignored by this solver"); // The option Vectorized will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vrodasvectorize = odepkg_auxiliary_getmapvalue ("Vectorized", vodeopt); if (!vrodasvectorize.is_empty ()) if (vrodasvectorize.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"Vectorized\" will be ignored by this solver"); // Implementation of the option 'Mass' has been finished, these // options can be set by the user to another value than default vrodasmass = odepkg_auxiliary_getmapvalue ("Mass", vodeopt); octave_idx_type vrodasmas = 0; if (!vrodasmass.is_empty ()) { vrodasmas = 1; if (vrodasmass.is_function_handle () || vrodasmass.is_inline_function ()) warning_with_id ("OdePkg:InvalidOption", "Option \"Mass\" only supports constant mass matrices M() and not M(t,y)"); } // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option vrodasmassstate = odepkg_auxiliary_getmapvalue ("MStateDependence", vodeopt); if (!vrodasmassstate.is_empty ()) if (vrodasmassstate.string_value ().compare ("weak") != 0) // 'weak' is default warning_with_id ("OdePkg:InvalidOption", "Option \"MStateDependence\" will be ignored by this solver"); // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmvpat = odepkg_auxiliary_getmapvalue ("MvPattern", vodeopt); if (!vmvpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MvPattern\" will be ignored by this solver"); // The option MassSingular will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmsing = odepkg_auxiliary_getmapvalue ("MassSingular", vodeopt); if (!vmsing.is_empty ()) if (vmsing.string_value ().compare ("maybe") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MassSingular\" will be ignored by this solver"); // The option InitialSlope will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vinitslope = odepkg_auxiliary_getmapvalue ("InitialSlope", vodeopt); if (!vinitslope.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialSlope\" will be ignored by this solver"); // The option MaxOrder will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vmaxder = odepkg_auxiliary_getmapvalue ("MaxOrder", vodeopt); if (!vmaxder.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" will be ignored by this solver"); // The option BDF will be ignored by this solver, the core Fortran // solver doesn't support this option octave_value vbdf = odepkg_auxiliary_getmapvalue ("BDF", vodeopt); if (!vbdf.is_empty ()) if (vbdf.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"BDF\" will be ignored by this solver"); // The option NewtonTol and MaxNewtonIterations will be ignored by // this solver, IT NEEDS TO BE CHECKED IF THE FORTRAN CORE SOLVER // CAN HANDLE THESE OPTIONS octave_value vntol = odepkg_auxiliary_getmapvalue ("NewtonTol", vodeopt); if (!vntol.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NewtonTol\" will be ignored by this solver"); octave_value vmaxnewton = odepkg_auxiliary_getmapvalue ("MaxNewtonIterations", vodeopt); if (!vmaxnewton.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" will be ignored by this solver"); /* Start MAINPROCESSING, set up all variables that are needed by this * solver and then initialize the solver function and get into the * main integration loop ********************************************************************/ NDArray vY0 = args(2).array_value (); NDArray vRTOL = vreltol.array_value (); NDArray vATOL = vabstol.array_value (); octave_idx_type N = args(2).length (); octave_idx_type IFCN = 1; double X = args(1).vector_value ()(0); double* Y = vY0.fortran_vec (); double XEND = args(1).vector_value ()(1); double H = vinitstep.double_value (); double *RTOL = vRTOL.fortran_vec (); double *ATOL = vATOL.fortran_vec (); octave_idx_type ITOL = vitol; octave_idx_type IJAC = vrodasjac; octave_idx_type MLJAC=N; octave_idx_type MUJAC=N; octave_idx_type IDFX=0; octave_idx_type IMAS=vrodasmas; octave_idx_type MLMAS=N; octave_idx_type MUMAS=N; octave_idx_type IOUT = 1; // The SOLOUT function will always be called octave_idx_type LWORK = N*(N+N+N+14)+20; OCTAVE_LOCAL_BUFFER (double, WORK, LWORK); for (octave_idx_type vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; octave_idx_type LIWORK = N+20; OCTAVE_LOCAL_BUFFER (octave_idx_type, IWORK, LIWORK); for (octave_idx_type vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; double RPAR[1] = {0.0}; octave_idx_type IPAR[1] = {0}; octave_idx_type IDID = 0; WORK[1] = vmaxstep.double_value (); // Set the maximum step size // Check if the user has set some of the options "OutputFcn", "Events" // etc. and initialize the plot, events and the solstore functions octave_value vtim = args(1).vector_value ()(0); octave_value vsol = args(2); odepkg_auxiliary_solstore (vtim, vsol, 0); if (!vrodaspltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vrodaspltfun, vrodasoutsel, args(1), args(2), vrodasextarg, 0); if (!vrodasevefun.is_empty ()) odepkg_auxiliary_evaleventfun (vrodasevefun, vtim, args(2), vrodasextarg, 0); // We are calling the core solver and solve the set of ODEs or DAEs F77_XFCN (rodas, RODAS, // Keep 5 arguments per line here (N, odepkg_rodas_usrfcn, IFCN, X, Y, XEND, H, RTOL, ATOL, ITOL, odepkg_rodas_jacfcn, IJAC, MLJAC, MUJAC, odepkg_rodas_dfxfcn, IDFX, odepkg_rodas_massfcn, IMAS, MLMAS, MUMAS, odepkg_rodas_solfcn, IOUT, WORK, LWORK, IWORK, LIWORK, RPAR, IPAR, IDID)); if (IDID < 0) { // odepkg_auxiliary_mebdfanalysis (IDID); error_with_id ("hugh:hugh", "missing implementation"); vretval(0) = 0.0; return (vretval); } /* Start POSTPROCESSING, check how many arguments should be returned * to the caller and check which extra arguments have to be set *******************************************************************/ // Return the results that have been stored in the // odepkg_auxiliary_solstore function octave_value vtres, vyres; odepkg_auxiliary_solstore (vtres, vyres, 2); // Set up variables to make it possible to call the cleanup // functions of 'OutputFcn' and 'Events' if any Matrix vlastline; vlastline = vyres.matrix_value (); vlastline = vlastline.extract (vlastline.rows () - 1, 0, vlastline.rows () - 1, vlastline.cols () - 1); octave_value vted = octave_value (XEND); octave_value vfin = octave_value (vlastline); if (!vrodaspltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vrodaspltfun, vrodasoutsel, vted, vfin, vrodasextarg, 2); if (!vrodasevefun.is_empty ()) odepkg_auxiliary_evaleventfun (vrodasevefun, vted, vfin, vrodasextarg, 2); // Get the stats information as an Octave_map if the option 'Stats' // has been set with odeset octave_value_list vstatinput; vstatinput(0) = IWORK[16]; vstatinput(1) = IWORK[17]; vstatinput(2) = IWORK[13]; vstatinput(3) = IWORK[14]; vstatinput(4) = IWORK[18]; vstatinput(5) = IWORK[19]; octave_value vstatinfo; if ((vstats.string_value ().compare ("on") == 0) && (nargout == 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, false); else if ((vstats.string_value ().compare ("on") == 0) && (nargout != 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, true); // Set up output arguments that depend on how many output arguments // are desired from the caller if (nargout == 1) { Octave_map vretmap; vretmap.assign ("x", vtres); vretmap.assign ("y", vyres); vretmap.assign ("solver", "oders"); if (!vstatinfo.is_empty ()) // Event implementation vretmap.assign ("stats", vstatinfo); if (!vrodasevefun.is_empty ()) { vretmap.assign ("ie", vrodasevesol(0).cell_value ()(1)); vretmap.assign ("xe", vrodasevesol(0).cell_value ()(2)); vretmap.assign ("ye", vrodasevesol(0).cell_value ()(3)); } vretval(0) = octave_value (vretmap); } else if (nargout == 2) { vretval(0) = vtres; vretval(1) = vyres; } else if (nargout == 5) { Matrix vempty; // prepare an empty matrix vretval(0) = vtres; vretval(1) = vyres; vretval(2) = vempty; vretval(3) = vempty; vretval(4) = vempty; if (!vrodasevefun.is_empty ()) { vretval(2) = vrodasevesol(0).cell_value ()(2); vretval(3) = vrodasevesol(0).cell_value ()(3); vretval(4) = vrodasevesol(0).cell_value ()(1); } } return (vretval); } /* %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference solut %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (size (vt) != [2, 1] && size (vt) != [1, 2]) %! error ('"fout" step "init"'); %! end %! elseif (isempty (vflag)) %! if (size (vt) ~= [1, 1]) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (size (vt) ~= [1, 1]) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = oders (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = oders (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = oders (@fpol, [0 25], 1); %!error %# fixed step sizes not supported %! B = oders (@fpol, [0:0.1:2], [2 0]); %!test %# one output argument %! vsol = oders (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'oders'); %!test %# two output arguments %! [vt, vy] = oders (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = oders (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = oders (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = oders (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = oders (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-4); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-4); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = oders (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-9); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = oders (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = oders (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = oders (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = oders (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 1e-1); %! warning ('on', 'OdePkg:HideWarning'); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set NewtonTol option to something else than default %! vopt = odeset ('NewtonTol', 1e-3); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set MaxNewtonIterations option to something else than default %! vopt = odeset ('MaxNewtonIterations', 2); %! vsol = oders (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! warning ('on', 'OdePkg:InvalidOption'); */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */ odepkg/src/odepkg_octsolver_seulex.cc0000644000176000010400000011570611711232766021262 0ustar marcoAdministrators/* Copyright (C) 2007-2012, Thomas Treichl OdePkg - A package for solving ordinary differential equations and more This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; If not, see . */ /* Compile this file manually and run some tests with the following command bash:~$ mkoctfile -v -Wall -W -Wshadow odepkg_octsolver_seulex.cc \ odepkg_auxiliary_functions.cc hairer/seulex.f hairer/dc_decsol.f \ hairer/decsol.f -o odesx.oct octave> octave --quiet --eval "autoload ('odesx', [pwd, '/odesx.oct']); \ test 'odepkg_octsolver_seulex.cc'" For an explanation about various parts of this source file cf. the source file odepkg_octsolver_rodas.cc. The implementation of that file is very similiar to the implementation of this file. */ #include #include #include #include #include #include "odepkg_auxiliary_functions.h" typedef octave_idx_type (*odepkg_seulex_usrtype) (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_seulex_jactype) (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_seulex_masstype) (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR); typedef octave_idx_type (*odepkg_seulex_soltype) (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* RC, const octave_idx_type& LRC, const double* IC, const octave_idx_type& LIC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN); extern "C" { F77_RET_T F77_FUNC (seulex, SEULEX) (const octave_idx_type& N, odepkg_seulex_usrtype, const octave_idx_type& IFCN, const double& X, const double* Y, const double& XEND, const double& H, const double* RTOL, const double* ATOL, const octave_idx_type& ITOL, odepkg_seulex_jactype, const octave_idx_type& IJAC, const octave_idx_type& MLJAC, const octave_idx_type& MUJAC, odepkg_seulex_masstype, const octave_idx_type& IMAS, const octave_idx_type& MLMAS, const octave_idx_type& MUMAS, odepkg_seulex_soltype, const octave_idx_type& IOUT, const double* WORK, const octave_idx_type& LWORK, const octave_idx_type* IWORK, const octave_idx_type& LIWORK, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, const octave_idx_type& IDID); double F77_FUNC (contex, CONTEX) (const octave_idx_type& I, const double& S, const double* RC, const octave_idx_type& LRC, const double* IC, const octave_idx_type& LIC); } // extern "C" static octave_value_list vseulexextarg; static octave_value vseulexodefun; static octave_value vseulexjacfun; static octave_value vseulexevefun; static octave_value vseulexevebrk; static octave_value_list vseulexevesol; static octave_value vseulexpltfun; static octave_value vseulexpltbrk; static octave_value vseulexoutsel; static octave_value vseulexrefine; static octave_value vseulexmass; static octave_value vseulexmassstate; octave_idx_type odepkg_seulex_usrfcn (const octave_idx_type& N, const double& X, const double* Y, double* F, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element wise, // otherwise Octave will crash if these variables will be freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) { A(vcnt) = Y[vcnt]; // octave_stdout << "I am here Y[" << vcnt << "] " << Y[vcnt] << std::endl; // octave_stdout << "I am here T " << X << std::endl; } // Fill the variable for the input arguments before evaluating the // function that keeps the set of differential algebraic equations octave_value_list varin; varin(0) = X; varin(1) = A; for (octave_idx_type vcnt = 0; vcnt < vseulexextarg.length (); vcnt++) varin(vcnt+2) = vseulexextarg(vcnt); octave_value_list vout = feval (vseulexodefun.function_value (), varin, 1); // Return the results from the function evaluation to the Fortran // solver, again copy them and don't just create a Fortran vector ColumnVector vcol = vout(0).column_vector_value (); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) F[vcnt] = vcol(vcnt); return (true); } octave_idx_type odepkg_seulex_jacfcn (const octave_idx_type& N, const double& X, const double* Y, double* DFY, GCC_ATTR_UNUSED const octave_idx_type& LDFY, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (X); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evaljacode (vseulexjacfun, vt, vy, vseulexextarg); Matrix vdfy = vout.matrix_value (); for (octave_idx_type vcol = 0; vcol < N; vcol++) for (octave_idx_type vrow = 0; vrow < N; vrow++) DFY[vrow+vcol*N] = vdfy (vrow, vcol); return (true); } F77_RET_T odepkg_seulex_massfcn (const octave_idx_type& N, double* AM, GCC_ATTR_UNUSED const octave_idx_type* LMAS, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = 0.0; // warning_with_id ("OdePkg:InvalidFunctionCall", // "Seulex can only handle M()=const Mass matrices"); // Set the values that are needed as input arguments before calling // the Jacobian function and then call the Jacobian interface octave_value vt = octave_value (0.0); octave_value vy = octave_value (A); octave_value vout = odepkg_auxiliary_evalmassode (vseulexmass, vseulexmassstate, vt, vy, vseulexextarg); Matrix vam = vout.matrix_value (); for (octave_idx_type vrow = 0; vrow < N; vrow++) for (octave_idx_type vcol = 0; vcol < N; vcol++) AM[vrow+vcol*N] = vam (vrow, vcol); return (true); } octave_idx_type odepkg_seulex_solfcn (const octave_idx_type& NR, const double& XOLD, const double& X, const double* Y, const double* RC, const octave_idx_type& LRC, const double* IC, const octave_idx_type& LIC, const octave_idx_type& N, GCC_ATTR_UNUSED const double* RPAR, GCC_ATTR_UNUSED const octave_idx_type* IPAR, octave_idx_type& IRTRN) { // Copy the values that come from the Fortran function element-wise, // otherwise Octave will crash if these variables are freed ColumnVector A(N); for (octave_idx_type vcnt = 0; vcnt < N; vcnt++) A(vcnt) = Y[vcnt]; // Set the values that are needed as input arguments before calling // the Output function, the solstore function or the Events function octave_value vt = octave_value (X); octave_value vy = octave_value (A); vseulexevebrk = false; // Check if an 'Events' function has been set by the user if (!vseulexevefun.is_empty ()) { vseulexevesol = odepkg_auxiliary_evaleventfun (vseulexevefun, vt, vy, vseulexextarg, 1); if (!vseulexevesol(0).cell_value ()(0).is_empty ()) if (vseulexevesol(0).cell_value ()(0).int_value () == 1) { ColumnVector vttmp = vseulexevesol(0).cell_value ()(2).column_vector_value (); Matrix vrtmp = vseulexevesol(0).cell_value ()(3).matrix_value (); vt = vttmp.extract (vttmp.length () - 1, vttmp.length () - 1); vy = vrtmp.extract (vrtmp.rows () - 1, 0, vrtmp.rows () - 1, vrtmp.cols () - 1); IRTRN = (vseulexevesol(0).cell_value ()(0).int_value () ? -1 : 0); vseulexevebrk = true; } } // Save the solutions that come from the Fortran core solver if this // is not the initial first call to this function if (NR > 1) odepkg_auxiliary_solstore (vt, vy, 1); // Check if an 'OutputFcn' has been set by the user (including the // values of the options for 'OutputSel' and 'Refine') vseulexpltbrk = false; if (!vseulexpltfun.is_empty ()) { if (vseulexrefine.int_value () > 0) { ColumnVector B(N); double vtb = 0.0; for (octave_idx_type vcnt = 1; vcnt < vseulexrefine.int_value (); vcnt++) { // Calculate time stamps between XOLD and X and get the // results at these time stamps vtb = (X - XOLD) * vcnt / vseulexrefine.int_value () + XOLD; for (octave_idx_type vcou = 0; vcou < N; vcou++) B(vcou) = F77_FUNC (contex, CONTEX) (vcou+1, vtb, RC, LRC, IC, LIC); // Evaluate the 'OutputFcn' with the approximated values from // the F77_FUNC before the output of the results is done octave_value vyr = octave_value (B); octave_value vtr = octave_value (vtb); odepkg_auxiliary_evalplotfun (vseulexpltfun, vseulexoutsel, vtr, vyr, vseulexextarg, 1); } } // Evaluate the 'OutputFcn' with the results from the solver, if // the OutputFcn returns true then set a negative value in IRTRN IRTRN = - odepkg_auxiliary_evalplotfun (vseulexpltfun, vseulexoutsel, vt, vy, vseulexextarg, 1); vseulexpltbrk = true; } return (true); } // PKG_ADD: autoload ("odesx", "dldsolver.oct"); DEFUN_DLD (odesx, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Command} {[@var{}] =} odesx (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{sol}] =} odesx (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ @deftypefnx {Command} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} odesx (@var{@@fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])\n\ \n\ This function file can be used to solve a set of stiff ordinary differential equations (ODEs) and stiff differential algebraic equations (DAEs). This function file is a wrapper to Hairer's and Wanner's Fortran solver @file{seulex.f}.\n\ \n\ If this function is called with no return argument then plot the solution over time in a figure window while solving the set of ODEs that are defined in a function and specified by the function handle @var{@@fun}. The second input argument @var{slot} is a double vector that defines the time slot, @var{init} is a double vector that defines the initial values of the states, @var{opt} can optionally be a structure array that keeps the options created with the command @command{odeset} and @var{par1}, @var{par2}, @dots{} can optionally be other input arguments of any type that have to be passed to the function defined by @var{@@fun}.\n\ \n\ If this function is called with one return argument then return the solution @var{sol} of type structure array after solving the set of ODEs. The solution @var{sol} has the fields @var{x} of type double column vector for the steps chosen by the solver, @var{y} of type double column vector for the solutions at each time step of @var{x}, @var{solver} of type string for the solver name and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector that keep the informations of the event function if an event function handle is set in the option argument @var{opt}.\n\ \n\ If this function is called with more than one return argument then return the time stamps @var{t}, the solution values @var{y} and optionally the extended time stamp information @var{xe}, the extended solution information @var{ye} and the extended index information @var{ie} all of type double column vector.\n\ \n\ For example,\n\ @example\n\ function y = odepkg_equations_lorenz (t, x)\n\ y = [10 * (x(2) - x(1));\n\ x(1) * (28 - x(3));\n\ x(1) * x(2) - 8/3 * x(3)];\n\ endfunction\n\ \n\ vopt = odeset (\"InitialStep\", 1e-3, \"MaxStep\", 1e-1, \\\n\ \"OutputFcn\", @@odephas3, \"Refine\", 5);\n\ odesx (@@odepkg_equations_lorenz, [0, 25], [3 15 1], vopt);\n\ @end example\n\ @end deftypefn\n\ \n\ @seealso{odepkg}") { octave_idx_type nargin = args.length (); // The number of input arguments octave_value_list vretval; // The cell array of return args Octave_map vodeopt; // The OdePkg options structure // Check number and types of all input arguments if (nargin < 3) { print_usage (); return (vretval); } // If args(0)==function_handle is valid then set the vseulexodefun // variable that has been defined "static" before if (!args(0).is_function_handle () && !args(0).is_inline_function ()) { error_with_id ("OdePkg:InvalidArgument", "First input argument must be a valid function handle"); return (vretval); } else // We store the args(0) argument in the static variable vseulexodefun vseulexodefun = args(0); // Check if the second input argument is a valid vector describing // the time window that should be solved, it may be of length 2 ONLY if (args(1).is_scalar_type () || !odepkg_auxiliary_isvector (args(1))) { error_with_id ("OdePkg:InvalidArgument", "Second input argument must be a valid vector"); return (vretval); } // Check if the thirt input argument is a valid vector describing // the initial values of the variables of the differential equations if (!odepkg_auxiliary_isvector (args(2))) { error_with_id ("OdePkg:InvalidArgument", "Third input argument must be a valid vector"); return (vretval); } // Check if there are further input arguments ie. the options // structure and/or arguments that need to be passed to the // OutputFcn, Events and/or Jacobian etc. if (nargin >= 4) { // Fourth input argument != OdePkg option, need a default structure if (!args(3).is_map ()) { octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure for (octave_idx_type vcnt = 3; vcnt < nargin; vcnt++) vseulexextarg(vcnt-3) = args(vcnt); // Save arguments in vseulexextarg } // Fourth input argument == OdePkg option, extra input args given too else if (nargin > 4) { octave_value_list varin; varin(0) = args(3); varin(1) = "odesx"; octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create structure from args(4) for (octave_idx_type vcnt = 4; vcnt < nargin; vcnt++) vseulexextarg(vcnt-4) = args(vcnt); // Save extra arguments } // Fourth input argument == OdePkg option, no extra input args given else { octave_value_list varin; varin(0) = args(3); varin(1) = "odesx"; // Check structure octave_value_list tmp = feval ("odepkg_structure_check", varin, 1); if (error_state) return (vretval); vodeopt = tmp(0).map_value (); // Create a default structure } } // if (nargin >= 4) else { // if nargin == 3, everything else has been checked before octave_value_list tmp = feval ("odeset", tmp, 1); vodeopt = tmp(0).map_value (); // Create a default structure } /* Start PREPROCESSING, ie. check which options have been set and * print warnings if there are options that can't be handled by this * solver or have not been implemented yet *******************************************************************/ // Implementation of the option RelTol has been finished, this // option can be set by the user to another value than default value octave_value vreltol = odepkg_auxiliary_getmapvalue ("RelTol", vodeopt); if (vreltol.is_empty ()) { vreltol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"RelTol\" not set, new value %3.1e is used", vreltol.double_value ()); } // vreltol.print (octave_stdout, true); return (vretval); if (!vreltol.is_scalar_type ()) { if (vreltol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"RelTol\" must be the same as the number of equations"); return (vretval); } } // Implementation of the option AbsTol has been finished, this // option can be set by the user to another value than default value octave_value vabstol = odepkg_auxiliary_getmapvalue ("AbsTol", vodeopt); if (vabstol.is_empty ()) { vabstol = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"AbsTol\" not set, new value %3.1e is used", vabstol.double_value ()); } // vabstol.print (octave_stdout, true); return (vretval); if (!vabstol.is_scalar_type ()) { if (vabstol.length () != args(2).length ()) { error_with_id ("OdePkg:InvalidOption", "Length of option \"AbsTol\" must be the same as the number of equations"); return (vretval); } } // Setting the tolerance type that depends on the types (scalar or // vector) of the options RelTol and AbsTol octave_idx_type vitol = 0; if (vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 0; else if (!vreltol.is_scalar_type () && (vreltol.length () == vabstol.length ())) vitol = 1; else { error_with_id ("OdePkg:InvalidOption", "Values of \"RelTol\" and \"AbsTol\" must have same length"); return (vretval); } // The option NormControl will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnorm = odepkg_auxiliary_getmapvalue ("NormControl", vodeopt); if (!vnorm.is_empty ()) if (vnorm.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"NormControl\" will be ignored by this solver"); // The option NonNegative will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vnneg = odepkg_auxiliary_getmapvalue ("NonNegative", vodeopt); if (!vnneg.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NonNegative\" will be ignored by this solver"); // Implementation of the option OutputFcn has been finished, this // option can be set by the user to another value than default value vseulexpltfun = odepkg_auxiliary_getmapvalue ("OutputFcn", vodeopt); if (vseulexpltfun.is_empty () && nargout == 0) vseulexpltfun = "odeplot"; // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vseulexoutsel = odepkg_auxiliary_getmapvalue ("OutputSel", vodeopt); // Implementation of the option OutputSel has been finished, this // option can be set by the user to another value than default value vseulexrefine = odepkg_auxiliary_getmapvalue ("Refine", vodeopt); // Implementation of the option Stats has been finished, this option // can be set by the user to another value than default value octave_value vstats = odepkg_auxiliary_getmapvalue ("Stats", vodeopt); // Implementation of the option InitialStep has been finished, this // option can be set by the user to another value than default value octave_value vinitstep = odepkg_auxiliary_getmapvalue ("InitialStep", vodeopt); if (args(1).length () > 2) { error_with_id ("OdePkg:InvalidOption", "Fixed time stamps are not supported by this solver"); } if (vinitstep.is_empty ()) { vinitstep = 1.0e-6; warning_with_id ("OdePkg:InvalidOption", "Option \"InitialStep\" not set, new value %3.1e is used", vinitstep.double_value ()); } // Implementation of the option MaxStep has been finished, this // option can be set by the user to another value than default value octave_value vmaxstep = odepkg_auxiliary_getmapvalue ("MaxStep", vodeopt); if (vmaxstep.is_empty () && args(1).length () == 2) { vmaxstep = (args(1).vector_value ()(1) - args(1).vector_value ()(0)) / 12.5; warning_with_id ("OdePkg:InvalidOption", "Option \"MaxStep\" not set, new value %3.1e is used", vmaxstep.double_value ()); } // Implementation of the option Events has been finished, this // option can be set by the user to another value than default // value, odepkg_structure_check already checks for a valid value vseulexevefun = odepkg_auxiliary_getmapvalue ("Events", vodeopt); // Implementation of the option 'Jacobian' has been finished, these // options can be set by the user to another value than default vseulexjacfun = odepkg_auxiliary_getmapvalue ("Jacobian", vodeopt); octave_idx_type vseulexjac = 0; // We need to set this if no Jac available if (!vseulexjacfun.is_empty ()) vseulexjac = 1; // The option JPattern will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vseulexjacpat = odepkg_auxiliary_getmapvalue ("JPattern", vodeopt); if (!vseulexjacpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"JPattern\" will be ignored by this solver"); // The option Vectorized will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vseulexvectorize = odepkg_auxiliary_getmapvalue ("Vectorized", vodeopt); if (!vseulexvectorize.is_empty ()) if (vseulexvectorize.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"Vectorized\" will be ignored by this solver"); // Implementation of the option 'Mass' has been finished, these // options can be set by the user to another value than default vseulexmass = odepkg_auxiliary_getmapvalue ("Mass", vodeopt); octave_idx_type vseulexmas = 0; if (!vseulexmass.is_empty ()) { vseulexmas = 1; if (vseulexmass.is_function_handle () || vseulexmass.is_inline_function ()) warning_with_id ("OdePkg:InvalidOption", "Option \"Mass\" only supports constant mass matrices M() and not M(t,y)"); } // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option vseulexmassstate = odepkg_auxiliary_getmapvalue ("MStateDependence", vodeopt); if (!vseulexmassstate.is_empty ()) if (vseulexmassstate.string_value ().compare ("weak") != 0) // 'weak' is default warning_with_id ("OdePkg:InvalidOption", "Option \"MStateDependence\" will be ignored by this solver"); // The option MStateDependence will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmvpat = odepkg_auxiliary_getmapvalue ("MvPattern", vodeopt); if (!vmvpat.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MvPattern\" will be ignored by this solver"); // The option MassSingular will be ignored by this solver, the // core Fortran solver doesn't support this option octave_value vmsing = odepkg_auxiliary_getmapvalue ("MassSingular", vodeopt); if (!vmsing.is_empty ()) if (vmsing.string_value ().compare ("maybe") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"MassSingular\" will be ignored by this solver"); // The option InitialSlope will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vinitslope = odepkg_auxiliary_getmapvalue ("InitialSlope", vodeopt); if (!vinitslope.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"InitialSlope\" will be ignored by this solver"); // The option MaxOrder will be ignored by this solver, the core // Fortran solver doesn't support this option octave_value vmaxder = odepkg_auxiliary_getmapvalue ("MaxOrder", vodeopt); if (!vmaxder.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxOrder\" will be ignored by this solver"); // The option BDF will be ignored by this solver, the core Fortran // solver doesn't support this option octave_value vbdf = odepkg_auxiliary_getmapvalue ("BDF", vodeopt); if (!vbdf.is_empty ()) if (vbdf.string_value ().compare ("off") != 0) warning_with_id ("OdePkg:InvalidOption", "Option \"BDF\" will be ignored by this solver"); // The option NewtonTol and MaxNewtonIterations will be ignored by // this solver, IT NEEDS TO BE CHECKED IF THE FORTRAN CORE SOLVER // CAN HANDLE THESE OPTIONS octave_value vntol = odepkg_auxiliary_getmapvalue ("NewtonTol", vodeopt); if (!vntol.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"NewtonTol\" will be ignored by this solver"); octave_value vmaxnewton = odepkg_auxiliary_getmapvalue ("MaxNewtonIterations", vodeopt); if (!vmaxnewton.is_empty ()) warning_with_id ("OdePkg:InvalidOption", "Option \"MaxNewtonIterations\" will be ignored by this solver"); /* Start MAINPROCESSING, set up all variables that are needed by this * solver and then initialize the solver function and get into the * main integration loop ********************************************************************/ NDArray vY0 = args(2).array_value (); NDArray vRTOL = vreltol.array_value (); NDArray vATOL = vabstol.array_value (); octave_idx_type N = args(2).length (); octave_idx_type IFCN = 1; double X = args(1).vector_value ()(0); double* Y = vY0.fortran_vec (); double XEND = args(1).vector_value ()(1); double H = vinitstep.double_value (); double *RTOL = vRTOL.fortran_vec (); double *ATOL = vATOL.fortran_vec (); octave_idx_type ITOL = vitol; octave_idx_type IJAC = vseulexjac; octave_idx_type MLJAC=N; octave_idx_type MUJAC=N; octave_idx_type IMAS=vseulexmas; octave_idx_type MLMAS=N; octave_idx_type MUMAS=N; octave_idx_type IOUT = 1; // The SOLOUT function will always be called octave_idx_type LWORK = N*(N+N+N+12+8)+4*12+20+(2+12*(12+3)/2)*N; OCTAVE_LOCAL_BUFFER (double, WORK, LWORK); for (octave_idx_type vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; octave_idx_type LIWORK = 2*N+12+20+N; OCTAVE_LOCAL_BUFFER (octave_idx_type, IWORK, LIWORK); for (octave_idx_type vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; double RPAR[1] = {0.0}; octave_idx_type IPAR[1] = {0}; octave_idx_type IDID = 0; IWORK[0] = 1; // Switch for transformation of Jacobian into Hessenberg form WORK[2] = -1; // Recompute Jacobian after every succesful step WORK[6] = vmaxstep.double_value (); // Set the maximum step size // Check if the user has set some of the options "OutputFcn", "Events" // etc. and initialize the plot, events and the solstore functions octave_value vtim = args(1).vector_value ()(0); octave_value vsol = args(2); odepkg_auxiliary_solstore (vtim, vsol, 0); if (!vseulexpltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vseulexpltfun, vseulexoutsel, args(1), args(2), vseulexextarg, 0); if (!vseulexevefun.is_empty ()) odepkg_auxiliary_evaleventfun (vseulexevefun, vtim, args(2), vseulexextarg, 0); // We are calling the core solver and solve the set of ODEs or DAEs F77_XFCN (seulex, SEULEX, // Keep 5 arguments per line here (N, odepkg_seulex_usrfcn, IFCN, X, Y, XEND, H, RTOL, ATOL, ITOL, odepkg_seulex_jacfcn, IJAC, MLJAC, MUJAC, odepkg_seulex_massfcn, IMAS, MLMAS, MUMAS, odepkg_seulex_solfcn, IOUT, WORK, LWORK, IWORK, LIWORK, RPAR, IPAR, IDID)); // If the solver reported IDID < 0 then an error occured. *BUT* the // seulex solver also reports an error if no error occurs but a user // break is done because of the 'OutputFcn' or the 'Events' if (IDID < 0 && (vseulexpltbrk.bool_value () == false) && (vseulexevebrk.bool_value () == false)) { error_with_id ("hugh:hugh", "missing implementation, error after solving %d", IDID); vretval(0) = 0.0; return (vretval); } /* Start POSTPROCESSING, check how many arguments should be returned * to the caller and check which extra arguments have to be set *******************************************************************/ // Return the results that have been stored in the // odepkg_auxiliary_solstore function octave_value vtres, vyres; odepkg_auxiliary_solstore (vtres, vyres, 2); // Set up variables to make it possible to call the cleanup // functions of 'OutputFcn' and 'Events' if any Matrix vlastline; vlastline = vyres.matrix_value (); vlastline = vlastline.extract (vlastline.rows () - 1, 0, vlastline.rows () - 1, vlastline.cols () - 1); octave_value vted = octave_value (XEND); octave_value vfin = octave_value (vlastline); if (!vseulexpltfun.is_empty ()) odepkg_auxiliary_evalplotfun (vseulexpltfun, vseulexoutsel, vted, vfin, vseulexextarg, 2); if (!vseulexevefun.is_empty ()) odepkg_auxiliary_evaleventfun (vseulexevefun, vted, vfin, vseulexextarg, 2); // Get the stats information as an Octave_map if the option 'Stats' // has been set with odeset octave_value_list vstatinput; vstatinput(0) = IWORK[16]; vstatinput(1) = IWORK[17]; vstatinput(2) = IWORK[13]; vstatinput(3) = IWORK[14]; vstatinput(4) = IWORK[18]; vstatinput(5) = IWORK[19]; octave_value vstatinfo; if ((vstats.string_value ().compare ("on") == 0) && (nargout == 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, false); else if ((vstats.string_value ().compare ("on") == 0) && (nargout != 1)) vstatinfo = odepkg_auxiliary_makestats (vstatinput, true); // Set up output arguments that depend on how many output arguments // are desired from the caller if (nargout == 1) { Octave_map vretmap; vretmap.assign ("x", vtres); vretmap.assign ("y", vyres); vretmap.assign ("solver", "odesx"); if (!vstatinfo.is_empty ()) // Event implementation vretmap.assign ("stats", vstatinfo); if (!vseulexevefun.is_empty ()) { vretmap.assign ("ie", vseulexevesol(0).cell_value ()(1)); vretmap.assign ("xe", vseulexevesol(0).cell_value ()(2)); vretmap.assign ("ye", vseulexevesol(0).cell_value ()(3)); } vretval(0) = octave_value (vretmap); } else if (nargout == 2) { vretval(0) = vtres; vretval(1) = vyres; } else if (nargout == 5) { Matrix vempty; // prepare an empty matrix vretval(0) = vtres; vretval(1) = vyres; vretval(2) = vempty; vretval(3) = vempty; vretval(4) = vempty; if (!vseulexevefun.is_empty ()) { vretval(2) = vseulexevesol(0).cell_value ()(2); vretval(3) = vseulexevesol(0).cell_value ()(3); vretval(4) = vseulexevesol(0).cell_value ()(1); } } return (vretval); } /* %! # We are using the "Van der Pol" implementation for all tests that %! # are done for this function. We also define a Jacobian, Events, %! # pseudo-Mass implementation. For further tests we also define a %! # reference solution (computed at high accuracy) and an OutputFcn %!function [ydot] = fpol (vt, vy, varargin) %# The Van der Pol %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %!function [vjac] = fjac (vt, vy, varargin) %# its Jacobian %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]; %!function [vjac] = fjcc (vt, vy, varargin) %# sparse type %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2]); %!function [vval, vtrm, vdir] = feve (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = zeros (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin) %! vval = fpol (vt, vy, varargin); %# We use the derivatives %! vtrm = ones (2,1); %# that's why component 2 %! vdir = ones (2,1); %# seems to not be exact %!function [vmas] = fmas (vt, vy) %! vmas = [1, 0; 0, 1]; %# Dummy mass matrix for tests %!function [vmas] = fmsa (vt, vy) %! vmas = sparse ([1, 0; 0, 1]); %# A sparse dummy matrix %!function [vref] = fref () %# The computed reference solut %! vref = [0.32331666704577, -1.83297456798624]; %!function [vout] = fout (vt, vy, vflag, varargin) %! if (regexp (char (vflag), 'init') == 1) %! if (size (vt) != [2, 1] && size (vt) != [1, 2]) %! error ('"fout" step "init"'); %! end %! elseif (isempty (vflag)) %! if (size (vt) ~= [1, 1]) error ('"fout" step "calc"'); end %! vout = false; %! elseif (regexp (char (vflag), 'done') == 1) %! if (size (vt) ~= [1, 1]) error ('"fout" step "done"'); end %! else error ('"fout" invalid vflag'); %! end %! %! %# Turn off output of warning messages for all tests, turn them on %! %# again if the last test is called %!error %# input argument number one %! warning ('off', 'OdePkg:InvalidOption'); %! B = odesx (1, [0 25], [3 15 1]); %!error %# input argument number two %! B = odesx (@fpol, 1, [3 15 1]); %!error %# input argument number three %! B = odesx (@fpol, [0 25], 1); %!error %# fixed step sizes not supported %! B = odesx (@fpol, [0:0.1:2], [2 0]); %!test %# one output argument %! vsol = odesx (@fpol, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! assert (isfield (vsol, 'solver')); %! assert (vsol.solver, 'odesx'); %!test %# two output arguments %! [vt, vy] = odesx (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %!test %# five output arguments and no Events %! [vt, vy, vxe, vye, vie] = odesx (@fpol, [0 2], [2 0]); %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3); %! assert ([vie, vxe, vye], []); %!test %# anonymous function instead of real function %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)]; %! vsol = odesx (fvdb, [0 2], [2 0]); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# extra input arguments passed trhough %! vsol = odesx (@fpol, [0 2], [2 0], 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# empty OdePkg structure *but* extra input arguments %! vopt = odeset; %! vsol = odesx (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL'); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!error %# strange OdePkg structure %! vopt = struct ('foo', 1); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %!test %# AbsTol option %! vopt = odeset ('AbsTol', 1e-5); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# AbsTol and RelTol option %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# RelTol and NormControl option -- higher accuracy %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on'); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Keeps initial values while integrating %! vopt = odeset ('NonNegative', 2); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-6); %!test %# Details of OutputSel and Refine can't be tested %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %!test %# Stats must add further elements in vsol %! vopt = odeset ('Stats', 'on'); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert (isfield (vsol, 'stats')); %! assert (isfield (vsol.stats, 'nsteps')); %!test %# InitialStep option %! vopt = odeset ('InitialStep', 1e-8); %! vsol = odesx (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(2)-vsol.x(1)], [1e-8], 1e-5); %!test %# MaxStep option %! vopt = odeset ('MaxStep', 1e-2); %! vsol = odesx (@fpol, [0 0.2], [2 0], vopt); %! assert ([vsol.x(5)-vsol.x(4)], [1e-2], 1e-2); %!test %# Events option add further elements in vsol %! vopt = odeset ('Events', @feve); %! vsol = odesx (@fpol, [0 10], [2 0], vopt); %! assert (isfield (vsol, 'ie')); %! assert (vsol.ie(1), 2); %! assert (isfield (vsol, 'xe')); %! assert (isfield (vsol, 'ye')); %!test %# Events option, now stop integration %! warning ('off', 'OdePkg:HideWarning'); %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! vsol = odesx (@fpol, [0 10], [2 0], vopt); %! assert ([vsol.ie, vsol.xe, vsol.ye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 0.5); %!test %# Events option, five output arguments %! vopt = odeset ('Events', @fevn, 'NormControl', 'on'); %! [vt, vy, vxe, vye, vie] = odesx (@fpol, [0 10], [2 0], vopt); %! assert ([vie, vxe, vye], ... %! [2.0, 2.496110, -0.830550, -2.677589], 0.5); %! warning ('on', 'OdePkg:HideWarning'); %!test %# Jacobian option %! vopt = odeset ('Jacobian', @fjac); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Jacobian option and sparse return value %! vopt = odeset ('Jacobian', @fjcc); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for JPattern option is missing %! %# test for Vectorized option is missing %! %!test %# Mass option as function %! vopt = odeset ('Mass', @fmas); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as matrix %! vopt = odeset ('Mass', eye (2,2)); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as sparse matrix %! vopt = odeset ('Mass', sparse (eye (2,2))); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and sparse matrix %! vopt = odeset ('Mass', @fmsa); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Mass option as function and MStateDependence %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong'); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! %# test for MvPattern option is missing %! %# test for InitialSlope option is missing %! %# test for MaxOrder option is missing %! %!test %# Set BDF option to something else than default %! vopt = odeset ('BDF', 'on'); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set NewtonTol option to something else than default %! vopt = odeset ('NewtonTol', 1e-3); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %!test %# Set MaxNewtonIterations option to something else than default %! vopt = odeset ('MaxNewtonIterations', 2); %! vsol = odesx (@fpol, [0 2], [2 0], vopt); %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3); %! %! warning ('on', 'OdePkg:InvalidOption'); */ /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */