├── LICENSE ├── README.md └── py36-src ├── MC_double.py ├── Newton.py ├── Newton_demo.py ├── Newton_system.py ├── Newtons_method.py ├── SIR1.py ├── SIR2.py ├── SIRV1.py ├── SIRV2.py ├── Taylor_exp.py ├── average_height.py ├── ball.py ├── ball_angle.py ├── ball_angle_first_try.py ├── ball_angle_prefix.py ├── ball_function.py ├── ball_max_height.py ├── ball_plot.py ├── ball_position_xy.py ├── ball_time.py ├── beam_vib.py ├── bisection_method.py ├── bisection_method_with_timing.py ├── brute_force_optimizer.py ├── brute_force_root_finder_flat.py ├── brute_force_root_finder_function.py ├── check_functions.py ├── compare_integration_methods.py ├── example_symbolic.py ├── file_handling.py ├── file_handling_numpy.py ├── format_string.py ├── formatted_columns.py ├── formatted_print.py ├── function_as_argument.py ├── growth1.py ├── integration_methods_vec.py ├── logistic.py ├── midpoint.py ├── midpoint_double.py ├── midpoint_triple.py ├── naive_Newton.py ├── nonlinear_solvers.py ├── nonlinear_solvers_rates.py ├── ode_FE.py ├── ode_system_FE.py ├── osc_2nd_order.py ├── osc_EC.py ├── osc_EC_general.py ├── osc_FE.py ├── osc_Heun.py ├── osc_RK4.py ├── osc_odespy.py ├── osc_odespy_general.py ├── plot_multiple_curves.py ├── print_columns.py ├── print_rates.py ├── random_walk_2D.py ├── rate_exponential.py ├── rate_piecewise_constant.py ├── rod_BE.py ├── rod_FE.py ├── rod_FE_scaled.py ├── rod_FE_vec.py ├── rod_odespy.py ├── rod_units.py ├── search_solutions_1eqn.py ├── secant_method.py ├── swim_advisor.py ├── system_nonlin_eqns_Newton.py ├── test_diffusion_pde_exact_linear.py ├── test_ode_FE_exact_linear.py ├── test_trapezoidal.py ├── throw_2_dice.py ├── times_tables_1.py ├── times_tables_2.py ├── times_tables_3.py ├── times_tables_4.py ├── timing_function_call.py ├── timing_midpoint_vec.py ├── trapezoidal.py ├── trapezoidal_flat.py ├── trapezoidal_flat1.py ├── two_plots_one_fig.py ├── vertical_motion.py ├── viz_midpoint.py ├── viz_rectangle.py └── viz_trapezoidal.py /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # prog4comp_2 2 | Resources for the 2nd edition of "Programming for Computations" by S. Linge and H.P. Langtangen 3 | -------------------------------------------------------------------------------- /py36-src/MC_double.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def MonteCarlo_double(f, g, x0, x1, y0, y1, n): 4 | """ 5 | Monte Carlo integration of f over a domain g>=0, embedded 6 | in a rectangle [x0,x1]x[y0,y1]. n^2 is the number of 7 | random points. 8 | """ 9 | # Draw n**2 random points in the rectangle 10 | x = np.random.uniform(x0, x1, n) 11 | y = np.random.uniform(y0, y1, n) 12 | # Compute sum of f values inside the integration domain 13 | f_mean = 0 14 | num_inside = 0 # number of x,y points inside domain (g>=0) 15 | for i in range(len(x)): 16 | for j in range(len(y)): 17 | if g(x[i], y[j]) >= 0: 18 | num_inside = num_inside + 1 19 | f_mean = f_mean + f(x[i], y[j]) 20 | f_mean = f_mean/num_inside 21 | area = num_inside/(n**2)*(x1 - x0)*(y1 - y0) 22 | return area*f_mean 23 | 24 | def test_MonteCarlo_double_rectangle_area(): 25 | """Check the area of a rectangle.""" 26 | def g(x, y): 27 | return (1 if (0 <= x <= 2 and 3 <= y <= 4.5) else -1) 28 | 29 | x0 = 0; x1 = 3; y0 = 2; y1 = 5 # embedded rectangle 30 | n = 1000 31 | np.random.seed(8) # must fix the seed! 32 | I_expected = 3.121092 # computed with this seed 33 | I_computed = MonteCarlo_double( 34 | lambda x, y: 1, g, x0, x1, y0, y1, n) 35 | assert abs(I_expected - I_computed) < 1E-14 36 | 37 | def test_MonteCarlo_double_circle_r(): 38 | """Check the integral of r over a circle with radius 2.""" 39 | def g(x, y): 40 | xc, yc = 0, 0 # center 41 | R = 2 # radius 42 | return R**2 - ((x-xc)**2 + (y-yc)**2) 43 | 44 | # Exact: integral of r*r*dr over circle with radius R becomes 45 | # 2*pi*1/3*R**3 46 | import sympy 47 | r = sympy.symbols('r') 48 | I_exact = sympy.integrate(2*sympy.pi*r*r, (r, 0, 2)) 49 | print('Exact integral: {:g}'.format(I_exact.evalf())) 50 | x0 = -2; x1 = 2; y0 = -2; y1 = 2 51 | n = 1000 52 | np.random.seed(6) 53 | I_expected = 16.7970837117376384 # Computed with this seed 54 | I_computed = MonteCarlo_double( 55 | lambda x, y: np.sqrt(x**2 + y**2), 56 | g, x0, x1, y0, y1, n) 57 | print('MC approximation, {:d} samples: {:.16f}'\ 58 | .format(n**2, I_computed)) 59 | assert abs(I_expected - I_computed) < 1E-15 60 | 61 | if __name__ == '__main__': 62 | test_MonteCarlo_double_rectangle_area() 63 | test_MonteCarlo_double_circle_r() -------------------------------------------------------------------------------- /py36-src/Newton.py: -------------------------------------------------------------------------------- 1 | def Newton(f, x, dfdx, epsilon=1.0E-7, N=100, store=False): 2 | f_value = f(x) 3 | n = 0 4 | if store: info = [(x, f_value)] 5 | while abs(f_value) > epsilon and n <= N: 6 | dfdx_value = float(dfdx(x)) 7 | if abs(dfdx_value) < 1E-14: 8 | raise ValueError("Newton: f'(%g)=%g" % (x, dfdx_value)) 9 | 10 | x = x - f_value/dfdx_value 11 | 12 | n += 1 13 | f_value = f(x) 14 | if store: info.append((x, f_value)) 15 | if store: 16 | return x, info 17 | else: 18 | return x, n, f_value 19 | 20 | 21 | def _g(x): 22 | return exp(-0.1*x**2)*sin(pi/2*x) 23 | 24 | def _dg(x): 25 | return -2*0.1*x*exp(-0.1*x**2)*sin(pi/2*x) + \ 26 | pi/2*exp(-0.1*x**2)*cos(pi/2*x) 27 | 28 | def _test(): 29 | from scitools.std import sin, cos, exp, linspace, plot, pi 30 | import sys 31 | 32 | x0 = float(sys.argv[1]) 33 | x, info = Newton(_g, x0, _dg, store=True) 34 | print 'root: %.16g' % x 35 | for i in range(len(info)): 36 | print 'Iteration %2d: f(%g)=%g' % \ 37 | (i, info[i][0], info[i][1]) 38 | 39 | x = linspace(-7, 7, 401) 40 | y = _g(x) 41 | plot(x, y) 42 | 43 | if __name__ == '__main__': 44 | _test() 45 | 46 | 47 | -------------------------------------------------------------------------------- /py36-src/Newton_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a program for illustrating the convergence of Newton's method 3 | for solving nonlinear algebraic equations of the form f(x) = 0. 4 | 5 | Usage: 6 | python Newton_movie.py f_formula df_formula x0 xmin xmax 7 | 8 | where f_formula is a string formula for f(x); df_formula is 9 | a string formula for the derivative f'(x), or df_formula can 10 | be the string 'numeric', which implies that f'(x) is computed 11 | numerically; x0 is the initial guess of the root; and the 12 | x axis in the plot has extent [xmin, xmax]. 13 | """ 14 | from Newton import Newton 15 | from scitools.std import * 16 | import matplotlib.pyplot as plt 17 | plt.xkcd() # cartoon style 18 | import sys 19 | 20 | def line(x0, y0, dydx): 21 | """ 22 | Find a and b for a line a*x+b that goes through (x0,y0) 23 | and has the derivative dydx at this point. 24 | 25 | Formula: y = y0 + dydx*(x - x0) 26 | """ 27 | return dydx, y0 - dydx*x0 28 | 29 | 30 | def illustrate_Newton(info, f, df, xmin, xmax): 31 | # First make a plot f for the x values that are in info 32 | xvalues = linspace(xmin, xmax, 401) 33 | fvalues = f(xvalues) 34 | ymin = fvalues.min(); ymax = fvalues.max() 35 | frame_counter = 0 36 | 37 | # Go through all x points (roots) and corresponding values 38 | # for each iteration and plot a green line from the x axis up 39 | # to the point (root,value), construct and plot the tangent at 40 | # this point, then plot the function curve, the tangent, 41 | # and the green line, 42 | # repeat this for all iterations and store hardcopies for making 43 | # a movie. 44 | 45 | for root, value in info: 46 | a, b = line(root, value, df(root)) 47 | y = a*xvalues + b 48 | raw_input('Type CR to continue: ') 49 | plt.figure() 50 | plt.plot(xvalues, fvalues, 'r-', 51 | [root, root], [ymin, value], 'g-', 52 | [xvalues[0], xvalues[-1]], [0,0], 'k--', 53 | xvalues, y, 'b-') 54 | plt.legend(['f(x)', 'approx. root', 'y=0', 'approx. line']) 55 | plt.axis([xmin, xmax, ymin, ymax]) 56 | plt.title("Newton's method, iter. %d: x=%g; f(%g)=%.3E" % (frame_counter+1, root, root, value)) 57 | plt.savefig('tmp_root_%04d.pdf' % frame_counter) 58 | plt.savefig('tmp_root_%04d.png' % frame_counter) 59 | frame_counter += 1 60 | 61 | try: 62 | f_formula = sys.argv[1] 63 | df_formula = sys.argv[2] 64 | x0 = float(sys.argv[3]) 65 | xmin = float(sys.argv[4]) 66 | xmax = float(sys.argv[5]) 67 | except IndexError: 68 | print 'f_formula df_formula x0 xmin max' 69 | sys.exit(1) 70 | 71 | # Clean up all plot files 72 | import glob, os 73 | for filename in glob.glob('tmp_*.pdf'): 74 | os.remove(filename) 75 | 76 | f = StringFunction(f_formula) 77 | f.vectorize(globals()) 78 | if df_formula == 'numeric': 79 | # Make a numerical differentiation formula 80 | h = 1.0E-7 81 | def df(x): 82 | return (f(x+h) - f(x-h))/(2*h) 83 | else: 84 | df = StringFunction(df_formula) 85 | df.vectorize(globals()) 86 | x, info = Newton(f, x0, df, store=True) 87 | illustrate_Newton(info, f, df, xmin, xmax) 88 | plt.show() 89 | -------------------------------------------------------------------------------- /py36-src/Newton_system.py: -------------------------------------------------------------------------------- 1 | """Use Newton's method to solve systems of nonlinear algebraic equations.""" 2 | import numpy as np 3 | 4 | def Newton_system(F, J, x, eps): 5 | """ 6 | Solve nonlinear system F=0 by Newton's method. 7 | J is the Jacobian of F. Both F and J must be functions of x. 8 | At input, x holds the start value. The iteration continues 9 | until ||F|| < eps. 10 | """ 11 | F_value = F(x) 12 | F_norm = np.linalg.norm(F_value, ord=2) # l2 norm of vector 13 | iteration_counter = 0 14 | while abs(F_norm) > eps and iteration_counter < 100: 15 | delta = np.linalg.solve(J(x), -F_value) 16 | x = x + delta 17 | F_value = F(x) 18 | F_norm = np.linalg.norm(F_value, ord=2) 19 | iteration_counter = iteration_counter + 1 20 | 21 | # Here, either a solution is found, or too many iterations 22 | if abs(F_norm) > eps: 23 | iteration_counter = -1 24 | return x, iteration_counter 25 | 26 | def test_Newton_system1(): 27 | from numpy import cos, sin, pi, exp 28 | 29 | def F(x): 30 | return np.array( 31 | [x[0]**2 - x[1] + x[0]*cos(pi*x[0]), 32 | x[0]*x[1] + exp(-x[1]) - x[0]**(-1.)]) 33 | 34 | def J(x): 35 | return np.array( 36 | [[2*x[0] + cos(pi*x[0]) - pi*x[0]*sin(pi*x[0]), -1], 37 | [x[1] + x[0]**(-2.), x[0] - exp(-x[1])]]) 38 | 39 | expected = np.array([1, 0]) 40 | tol = 1e-4 41 | x, n = Newton_system(F, J, x=np.array([2, -1]), eps=0.0001) 42 | print(n, x) 43 | error_norm = np.linalg.norm(expected - x, ord=2) 44 | assert error_norm < tol, 'norm of error ={:g}'.format(error_norm) 45 | print('norm of error ={:g}'.format(error_norm)) 46 | 47 | def test_Newton_system2(): 48 | 49 | def F(x): 50 | return np.array( 51 | [x[0]**2 - x[1] + x[0] - 2, 52 | x[1]*x[0] + x[1]**2 + x[0] - 1]) 53 | 54 | def J(x): 55 | return np.array( 56 | [[2*x[0] + 1, -1], 57 | [x[1] + 1, x[0] + 2*x[1]]]) 58 | 59 | expected = np.array([1, 0]) 60 | tol = 1e-4 61 | x, n = Newton_system(F, J, x=np.array([2, -0.5]), eps=0.0001) 62 | print(n, x) 63 | error_norm = np.linalg.norm(expected - x, ord=2) 64 | assert error_norm < tol, 'norm of error ={:g}'.format(error_norm) 65 | print('norm of error ={:g}'.format(error_norm)) 66 | 67 | if __name__ == '__main__': 68 | test_Newton_system1() 69 | test_Newton_system2() 70 | 71 | -------------------------------------------------------------------------------- /py36-src/Newtons_method.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def Newton(f, dfdx, x, eps): 4 | f_value = f(x) 5 | iteration_counter = 0 6 | while abs(f_value) > eps and iteration_counter < 100: 7 | try: 8 | x = x - f_value/dfdx(x) 9 | except ZeroDivisionError: 10 | print('Error! - derivative zero for x = ', x) 11 | sys.exit(1) # Abort with error 12 | 13 | f_value = f(x) 14 | iteration_counter = iteration_counter + 1 15 | 16 | # Here, either a solution is found, or too many iterations 17 | if abs(f_value) > eps: 18 | iteration_counter = -1 19 | return x, iteration_counter 20 | 21 | if __name__ == '__main__': 22 | def f(x): 23 | return x**2 - 9 24 | 25 | def dfdx(x): 26 | return 2*x 27 | 28 | solution, no_iterations = Newton(f, dfdx, x=1000, eps=1.0e-6) 29 | 30 | if no_iterations > 0: # Solution found 31 | print('Number of function calls: {:d}'.format(1+2*no_iterations)) 32 | print('A solution is: {:f}'.format(solution)) 33 | else: 34 | print('Solution not found!') 35 | -------------------------------------------------------------------------------- /py36-src/SIR1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | # Time unit: 1 h 5 | beta = 10./(40*8*24) 6 | gamma = 3./(15*24) 7 | dt = 0.1 # 6 min 8 | D = 30 # Simulate for D days 9 | N_t = int(D*24/dt) # Corresponding no of time steps 10 | 11 | t = np.linspace(0, N_t*dt, N_t+1) 12 | S = np.zeros(N_t+1) 13 | I = np.zeros(N_t+1) 14 | R = np.zeros(N_t+1) 15 | 16 | # Initial condition 17 | S[0] = 50 18 | I[0] = 1 19 | R[0] = 0 20 | 21 | # Step equations forward in time 22 | for n in range(N_t): 23 | S[n+1] = S[n] - dt*beta*S[n]*I[n] 24 | I[n+1] = I[n] + dt*beta*S[n]*I[n] - dt*gamma*I[n] 25 | R[n+1] = R[n] + dt*gamma*I[n] 26 | 27 | fig = plt.figure() 28 | l1, l2, l3 = plt.plot(t, S, t, I, t, R) 29 | fig.legend((l1, l2, l3), ('S', 'I', 'R'), 'center right') 30 | plt.xlabel('hours') 31 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 32 | plt.show() 33 | -------------------------------------------------------------------------------- /py36-src/SIR2.py: -------------------------------------------------------------------------------- 1 | """As the basic SIR1.py, but including loss of immunity.""" 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | # Time unit: 1 h 7 | #beta = 10./(40*8*24) 8 | #beta = 0.00033 # ca. beta/4, i.e. reduced compared to SIR1.py 9 | beta = 0.00043 10 | gamma = 3./(15*24) 11 | dt = 0.1 # 6 min 12 | D = 300 # Simulate for D days 13 | N_t = int(D*24/dt) # Corresponding no of hours 14 | #nu = 1./(24*50) # Average loss of immunity: 50 days 15 | nu = 1./(24*90) # Average loss of immunity: 90 days 16 | 17 | t = np.linspace(0, N_t*dt, N_t+1) 18 | S = np.zeros(N_t+1) 19 | I = np.zeros(N_t+1) 20 | R = np.zeros(N_t+1) 21 | 22 | # Initial condition 23 | S[0] = 50 24 | I[0] = 1 25 | R[0] = 0 26 | 27 | # Step equations forward in time 28 | for n in range(N_t): 29 | S[n+1] = S[n] - dt*beta*S[n]*I[n] + dt*nu*R[n] 30 | I[n+1] = I[n] + dt*beta*S[n]*I[n] - dt*gamma*I[n] 31 | R[n+1] = R[n] + dt*gamma*I[n] - dt*nu*R[n] 32 | 33 | fig = plt.figure() 34 | l1, l2, l3 = plt.plot(t, S, t, I, t, R) 35 | fig.legend((l1, l2, l3), ('S', 'I', 'R'), 'upper right') 36 | plt.xlabel('hours') 37 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 38 | plt.show() -------------------------------------------------------------------------------- /py36-src/SIRV1.py: -------------------------------------------------------------------------------- 1 | """As SIR2.py, but including constant vaccination.""" 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | # Time unit: 1 h 7 | beta = 10./(40*8*24) 8 | beta = beta=0.00033 # reduce beta to ca. beta/4 compared to SIR1.py 9 | print('beta:', beta) 10 | gamma = 3./(15*24) 11 | dt = 0.1 # 6 min 12 | D = 300 # Simulate for D days 13 | N_t = int(D*24/dt) # Corresponding no of hours 14 | nu = 1./(24*50) # Average loss of immunity: 50 days 15 | #p = 0.0005 16 | p = 0.0001 17 | 18 | t = np.linspace(0, N_t*dt, N_t+1) 19 | S = np.zeros(N_t+1) 20 | I = np.zeros(N_t+1) 21 | R = np.zeros(N_t+1) 22 | V = np.zeros(N_t+1) 23 | 24 | # Initial condition 25 | S[0] = 50 26 | I[0] = 1 27 | R[0] = 0 28 | V[0] = 0 29 | 30 | # Step equations forward in time 31 | for n in range(N_t): 32 | S[n+1] = S[n] - dt*beta*S[n]*I[n] + dt*nu*R[n] - dt*p*S[n] 33 | V[n+1] = V[n] + dt*p*S[n] 34 | I[n+1] = I[n] + dt*beta*S[n]*I[n] - dt*gamma*I[n] 35 | R[n+1] = R[n] + dt*gamma*I[n] - dt*nu*R[n] 36 | loss = int(V[n+1] + S[n+1] + R[n+1] + I[n+1]) - \ 37 | int(V[0] + S[0] + R[0] + I[0]) 38 | if loss > 0: 39 | print('loss: {:d}'.format(loss)) 40 | 41 | fig = plt.figure() 42 | l1, l2, l3, l4 = plt.plot(t, S, t, I, t, R, t, V) 43 | fig.legend((l1, l2, l3, l4), ('S', 'I', 'R', 'V'), 'upper right') 44 | plt.xlabel('hours') 45 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 46 | plt.show() -------------------------------------------------------------------------------- /py36-src/SIRV2.py: -------------------------------------------------------------------------------- 1 | """As SIRV1.py, but including time-dependent vaccination.""" 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | # Time unit: 1 h 7 | beta = 10./(40*8*24) 8 | beta /= 4 # Reduce beta compared to SIR1.py 9 | print('beta:', beta) 10 | gamma = 3./(15*24) 11 | dt = 0.1 # 6 min 12 | D = 100 # Simulate for D days 13 | N_t = int(D*24/dt) # Corresponding no of hours 14 | nu = 1./(24*50) # Average loss of immunity: 50 days 15 | 16 | t = np.linspace(0, N_t*dt, N_t+1) 17 | S = np.zeros(N_t+1) 18 | I = np.zeros(N_t+1) 19 | R = np.zeros(N_t+1) 20 | V = np.zeros(N_t+1) 21 | 22 | # Vaccination campaign 23 | p = np.zeros(N_t+1) 24 | start_index = int(6*24/dt) # 6 days = 6*24 h, div. by dt=0.1 gives intervals 25 | stop_index = int(15*24/dt) 26 | p[start_index:stop_index] = 0.005 27 | 28 | # Initial condition 29 | S[0] = 50 30 | I[0] = 1 31 | R[0] = 0 32 | V[0] = 0 33 | 34 | # Step equations forward in time 35 | for n in range(N_t): 36 | S[n+1] = S[n] - dt*beta*S[n]*I[n] + dt*nu*R[n] - dt*p[n]*S[n] 37 | V[n+1] = V[n] + dt*p[n]*S[n] 38 | I[n+1] = I[n] + dt*beta*S[n]*I[n] - dt*gamma*I[n] 39 | R[n+1] = R[n] + dt*gamma*I[n] - dt*nu*R[n] 40 | loss = int(V[n+1] + S[n+1] + R[n+1] + I[n+1]) - \ 41 | int(V[0] + S[0] + R[0] + I[0]) 42 | if loss > 0: 43 | print('loss: {:d}'.format(loss)) 44 | 45 | fig = plt.figure() 46 | l1, l2, l3, l4 = plt.plot(t, S, t, I, t, R, t, V) 47 | fig.legend((l1, l2, l3, l4), ('S', 'I', 'R', 'V'), 'upper right') 48 | plt.xlabel('hours') 49 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 50 | plt.show() -------------------------------------------------------------------------------- /py36-src/Taylor_exp.py: -------------------------------------------------------------------------------- 1 | from math import factorial 2 | from numpy import exp, linspace 3 | import matplotlib.pyplot as plt 4 | 5 | def f(x): 6 | """f(x) and its all its derivatives of higher order""" 7 | return exp(x) 8 | 9 | def T(x, c, N): 10 | """Builds the T.s. approxim. for f(x) = exp(x) with N + 1 terms""" 11 | sum = 0 12 | for n in range(N+1): 13 | # Note that f(c)=f'(c)=f''(c)..., when f(x) = exp(x) 14 | sum += (f(c)/factorial(n))*(x-c)**n 15 | return sum 16 | 17 | a = -3; b = 3; maxNoOfTerms = 4 18 | c = input('Give the parameter c: ') 19 | xPoints = linspace(a, b, 100) 20 | 21 | for i in range(maxNoOfTerms): 22 | Tapprox = T(xPoints, c, i) 23 | plt.plot(xPoints, f(xPoints), 'r', xPoints, Tapprox, '--') 24 | plt.axis([-4.0, 4.0, -2, 15]) 25 | plt.hold('on') 26 | plt.hold('off') 27 | plt.show() 28 | -------------------------------------------------------------------------------- /py36-src/average_height.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | N = 5 4 | h = np.zeros(N) # heights of family members (in meter) 5 | h[0] = 1.60; h[1] = 1.85; h[2] = 1.75; h[3] = 1.80; h[4] = 0.50 6 | 7 | sum = 0 8 | for i in [0, 1, 2, 3, 4]: 9 | sum = sum + h[i] 10 | average = sum/N 11 | 12 | print('Average height: {:g} meter'.format(average)) 13 | -------------------------------------------------------------------------------- /py36-src/ball.py: -------------------------------------------------------------------------------- 1 | # Program for computing the height of a ball in vertical motion 2 | 3 | v0 = 5 # Initial velocity 4 | g = 9.81 # Acceleration of gravity 5 | t = 0.6 # Time 6 | 7 | y = v0*t - 0.5*g*t**2 # Vertical position 8 | 9 | print(y) 10 | -------------------------------------------------------------------------------- /py36-src/ball_angle.py: -------------------------------------------------------------------------------- 1 | from math import atan, pi 2 | 3 | x = 10.0 # Horizontal position 4 | y = 10.0 # Vertical position 5 | 6 | angle = atan(y/x) 7 | 8 | print((angle/pi)*180) 9 | -------------------------------------------------------------------------------- /py36-src/ball_angle_first_try.py: -------------------------------------------------------------------------------- 1 | x = 10.0 # Horizontal position 2 | y = 10.0 # Vertical position 3 | 4 | angle = atan(y/x) 5 | 6 | print((angle/pi)*180) 7 | -------------------------------------------------------------------------------- /py36-src/ball_angle_prefix.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | x = 10.0 # Horizontal position 4 | y = 10.0 # Vertical position 5 | 6 | angle = math.atan(y/x) 7 | 8 | print((angle/math.pi)*180) 9 | -------------------------------------------------------------------------------- /py36-src/ball_function.py: -------------------------------------------------------------------------------- 1 | def y(v0, t): 2 | g = 9.81 # Acceleration of gravity 3 | return v0*t - 0.5*g*t**2 4 | 5 | v0 = 5 # Initial velocity 6 | 7 | time = 0.6 # Just pick one point in time 8 | print(y(v0, time)) 9 | time = 0.9 # Pick another point in time 10 | print(y(v0, time)) 11 | -------------------------------------------------------------------------------- /py36-src/ball_max_height.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | v0 = 5 # Initial velocity 5 | g = 9.81 # Acceleration of gravity 6 | t = np.linspace(0, 1, 1000) # 1000 points in time interval 7 | y = v0*t - 0.5*g*t**2 # Generate all heights 8 | 9 | # At this point, the array y with all the heights is ready, 10 | # and we need to find the largest value within y. 11 | 12 | largest_height = y[0] # Starting value for search 13 | for i in range(1, len(y), 1): 14 | if y[i] > largest_height: 15 | largest_height = y[i] 16 | 17 | print('The largest height achieved was {:g} m'.format(largest_height)) 18 | 19 | # We might also like to plot the path again just to compare 20 | plt.plot(t,y) 21 | plt.xlabel('Time (s)') 22 | plt.ylabel('Height (m)') 23 | plt.show() 24 | 25 | -------------------------------------------------------------------------------- /py36-src/ball_plot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | v0 = 5 5 | g = 9.81 6 | t = np.linspace(0, 1, 1001) 7 | 8 | y = v0*t - 0.5*g*t**2 9 | 10 | plt.plot(t, y) # plots all y coordinates vs. all t coordinates 11 | plt.xlabel('t (s)') # places the text t (s) on x-axis 12 | plt.ylabel('y (m)') # places the text y (m) on y-axis 13 | plt.show() # displays the figure 14 | -------------------------------------------------------------------------------- /py36-src/ball_position_xy.py: -------------------------------------------------------------------------------- 1 | def xy(v0x=2.0, v0y=5.0, t=0.6): 2 | """Computes horizontal and vertical positions at time t""" 3 | g = 9.81 # acceleration of gravity 4 | return v0x*t, v0y*t - 0.5*g*t**2 5 | 6 | x, y = xy() 7 | print('Horizontal position: {:g} , Vertical position: {:g}'.format(x, y)) 8 | 9 | -------------------------------------------------------------------------------- /py36-src/ball_time.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | v0 = 4.5 # Initial velocity 4 | g = 9.81 # Acceleration of gravity 5 | t = np.linspace(0, 1, 1000) # 1000 points in time interval 6 | y = v0*t - 0.5*g*t**2 # Generate all heights 7 | 8 | # Find index where ball approximately has reached y=0 9 | i = 0 10 | while y[i] >= 0: 11 | i = i + 1 12 | 13 | # Since y[i] is the height at time t[i], we do know the 14 | # time as well when we have the index i... 15 | print('Time of flight (in seconds): {:g}'.format(t[i])) 16 | 17 | # We plot the path again just for comparison 18 | import matplotlib.pyplot as plt 19 | plt.plot(t, y) 20 | plt.plot(t, 0*t, 'g--') 21 | plt.xlabel('Time (s)') 22 | plt.ylabel('Height (m)') 23 | plt.show() 24 | -------------------------------------------------------------------------------- /py36-src/beam_vib.py: -------------------------------------------------------------------------------- 1 | from numpy import * 2 | from matplotlib.pyplot import * 3 | 4 | def f(beta): 5 | return cosh(beta)*cos(beta) + 1 6 | 7 | def damped(beta): 8 | """Damp the amplitude of f. It grows like cosh, i.e. exp.""" 9 | return exp(-beta)*f(beta) 10 | 11 | def plot_f(): 12 | beta = linspace(0, 20, 501) 13 | #y = f(x) 14 | y = damped(beta) 15 | plot(beta, y, 'r', [beta[0], beta[-1]], [0, 0], 'b--') 16 | grid('on') 17 | xlabel(r'$\beta$') 18 | ylabel(r'$e^{-\beta}(\cosh\beta\cos\beta +1)$') 19 | savefig('tmp1.png'); savefig('tmp1.pdf') 20 | show() 21 | 22 | plot_f() 23 | 24 | from nonlinear_solvers import bisection 25 | # Set up suitable intervals 26 | intervals = [[1, 3], [4, 6], [7, 9]] 27 | betas = [] # roots 28 | for beta_L, beta_R in intervals: 29 | beta, it = bisection(f, beta_L, beta_R, eps=1E-6) 30 | betas.append(beta) 31 | print f(beta) 32 | print betas 33 | 34 | # Find corresponding frequencies 35 | 36 | def omega(beta, rho, A, E, I): 37 | return sqrt(beta**4/(rho*A/(E*I))) 38 | 39 | rho = 7850 # kg/m^3 40 | E = 1.0E+11 # Pa 41 | b = 0.025 # m 42 | h = 0.008 # m 43 | A = b*h 44 | I = b*h**3/12 45 | 46 | for beta in betas: 47 | print omega(beta, rho, A, E, I) 48 | -------------------------------------------------------------------------------- /py36-src/bisection_method.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def bisection(f, x_L, x_R, eps): 4 | f_L = f(x_L) 5 | if f_L*f(x_R) > 0: 6 | print("""Error! Function does not have opposite 7 | signs at interval endpoints!""") 8 | sys.exit(1) 9 | x_M = (x_L + x_R)/2.0 10 | f_M = f(x_M) 11 | iteration_counter = 1 12 | 13 | while abs(f_M) > eps: 14 | if f_L*f_M > 0: # i.e. same sign 15 | x_L = x_M 16 | f_L = f_M 17 | else: 18 | x_R = x_M 19 | x_M = (x_L + x_R)/2 20 | f_M = f(x_M) 21 | iteration_counter = iteration_counter + 1 22 | return x_M, iteration_counter 23 | 24 | if __name__ == '__main__': 25 | def f(x): 26 | return x**2 - 9 27 | 28 | a = 0; b = 1000 29 | 30 | solution, no_iterations = bisection(f, a, b, eps=1.0e-6) 31 | 32 | print('Number of function calls: {:d}'.format(1 + 2*no_iterations)) 33 | print('A solution is: {:f}'.format(solution)) 34 | -------------------------------------------------------------------------------- /py36-src/bisection_method_with_timing.py: -------------------------------------------------------------------------------- 1 | from timeit import * 2 | 3 | t = Timer('bisection(f, a, b, eps=1.0e-6)', 4 | setup=""" 5 | from nonlinear_solvers import bisection 6 | def f(x): 7 | return x**2 - 9 8 | 9 | a = 0; b = 1000 10 | """) 11 | no_runs = 100000 12 | print "CPU time (%d runs): %f" % (no_runs, t.timeit(no_runs)) 13 | 14 | -------------------------------------------------------------------------------- /py36-src/brute_force_optimizer.py: -------------------------------------------------------------------------------- 1 | def brute_force_optimizer(f, a, b, n): 2 | from numpy import linspace 3 | x = linspace(a, b, n) 4 | y = f(x) 5 | # Let maxima and minima hold the indices corresponding 6 | # to (local) maxima and minima points 7 | minima = [] 8 | maxima = [] 9 | for i in range(1, n-1): 10 | if y[i-1] < y[i] > y[i+1]: 11 | maxima.append(i) 12 | if y[i-1] > y[i] < y[i+1]: 13 | minima.append(i) 14 | 15 | # What about the end points? 16 | y_max_inner = max([y[i] for i in maxima]) 17 | y_min_inner = min([y[i] for i in minima]) 18 | if y[0] > y_max_inner: 19 | maxima.append(0) 20 | if y[len(x)-1] > y_max_inner: 21 | maxima.append(len(x)-1) 22 | if y[0] < y_min_inner: 23 | minima.append(0) 24 | if y[len(x)-1] < y_min_inner: 25 | minima.append(len(x)-1) 26 | 27 | # Return x and y values 28 | return [(x[i], y[i]) for i in minima], \ 29 | [(x[i], y[i]) for i in maxima] 30 | 31 | def demo(): 32 | from numpy import exp, cos 33 | minima, maxima = brute_force_optimizer( 34 | lambda x: exp(-x**2)*cos(4*x), 0, 4, 1001) 35 | print('Minima:\n', minima) 36 | print('Maxima:\n', maxima) 37 | 38 | if __name__ == '__main__': 39 | demo() 40 | -------------------------------------------------------------------------------- /py36-src/brute_force_root_finder_flat.py: -------------------------------------------------------------------------------- 1 | from numpy import linspace, exp, cos 2 | 3 | def f(x): 4 | return exp(-x**2)*cos(4*x) 5 | 6 | x = linspace(0, 4, 10001) 7 | y = f(x) 8 | 9 | root = None # Initialization 10 | for i in range(len(x)-1): 11 | if y[i]*y[i+1] < 0: 12 | root = x[i] - (x[i+1] - x[i])/(y[i+1] - y[i])*y[i] 13 | break # Jump out of loop 14 | elif y[i] == 0: 15 | root = x[i] 16 | break # Jump out of loop 17 | 18 | if root is None: 19 | print('Could not find any root in [{:g}, {:g}]'.format(x[0], x[-1])) 20 | else: 21 | print('Find (the first) root as x={:.17f}'.format(root)) 22 | -------------------------------------------------------------------------------- /py36-src/brute_force_root_finder_function.py: -------------------------------------------------------------------------------- 1 | def brute_force_root_finder(f, a, b, n): 2 | from numpy import linspace 3 | x = linspace(a, b, n) 4 | y = f(x) 5 | roots = [] 6 | for i in range(n-1): 7 | if y[i]*y[i+1] < 0: 8 | root = x[i] - (x[i+1] - x[i])/(y[i+1] - y[i])*y[i] 9 | roots.append(root) 10 | elif y[i] == 0: 11 | root = x[i] 12 | roots.append(root) 13 | return roots 14 | 15 | def demo(): 16 | from numpy import exp, cos 17 | roots = brute_force_root_finder( 18 | lambda x: exp(-x**2)*cos(4*x), 0, 4, 1001) 19 | if roots: 20 | print(roots) 21 | else: 22 | print('Could not find any roots') 23 | 24 | if __name__ == '__main__': 25 | demo() 26 | -------------------------------------------------------------------------------- /py36-src/check_functions.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math as m 3 | 4 | x = np.exp([0, 1, 2]) # do all 3 calculations 5 | print(x) # print all 3 results 6 | 7 | y = m.cos(0) 8 | print(y) 9 | -------------------------------------------------------------------------------- /py36-src/compare_integration_methods.py: -------------------------------------------------------------------------------- 1 | from trapezoidal import trapezoidal 2 | from midpoint import midpoint 3 | from math import exp 4 | 5 | g = lambda y: exp(-y**2) 6 | a = 0 7 | b = 2 8 | print(' n midpoint trapezoidal') 9 | for i in range(1, 21): 10 | n = 2**i 11 | m = midpoint(g, a, b, n) 12 | t = trapezoidal(g, a, b, n) 13 | print('{:7d} {:.16f} {:.16f}'.format(n, m, t)) 14 | -------------------------------------------------------------------------------- /py36-src/example_symbolic.py: -------------------------------------------------------------------------------- 1 | import sympy as sym 2 | 3 | x, y = sym.symbols('x y') 4 | 5 | print(2*x + 3*x - y) # Algebraic computation 6 | print(sym.diff(x**2, x)) # Differentiates x**2 wrt. x 7 | print(sym.integrate(sym.cos(x), x)) # Integrates cos(x) wrt. x 8 | print(sym.simplify((x**2 + x**3)/x**2)) # Simplifies expression 9 | print(sym.limit(sym.sin(x)/x, x, 0)) # lim of sin(x)/x as x->0 10 | print(sym.solve(5*x - 15, x)) # Solves 5*x = 15 11 | -------------------------------------------------------------------------------- /py36-src/file_handling.py: -------------------------------------------------------------------------------- 1 | filename = 'tmp.dat' 2 | infile = open(filename, 'r') # Open file for reading 3 | line = infile.readline() # Read first line 4 | # Read x and y coordinates from the file and store in lists 5 | x = [] 6 | y = [] 7 | for line in infile: # Read one line at a time 8 | words = line.split() # Split line into words 9 | x.append(float(words[0])) 10 | y.append(float(words[1])) 11 | infile.close() 12 | 13 | # Transform y coordinates 14 | from math import log 15 | 16 | def f(y): 17 | return log(y) 18 | 19 | for i in range(len(y)): 20 | y[i] = f(y[i]) 21 | 22 | # Write out x and y to a two-column file 23 | filename = 'tmp_out.dat' 24 | outfile = open(filename, 'w') # Open file for writing 25 | outfile.write('# x and y coordinates\n') 26 | for xi, yi in zip(x, y): 27 | outfile.write('{:10.5f} {:10.5f}\n'.format(xi, yi)) 28 | outfile.close() 29 | 30 | -------------------------------------------------------------------------------- /py36-src/file_handling_numpy.py: -------------------------------------------------------------------------------- 1 | filename = 'tmp.dat' 2 | import numpy 3 | data = numpy.loadtxt(filename, comments='#') 4 | x = data[:,0] 5 | y = data[:,1] 6 | data[:,1] = numpy.log(y) # insert transformed y back in array 7 | filename = 'tmp_out.dat' 8 | outfile = open(filename, 'w') # open file for writing 9 | outfile.write('# x and y coordinates\n') 10 | numpy.savetxt(outfile, data, fmt='%10.5f') 11 | 12 | -------------------------------------------------------------------------------- /py36-src/format_string.py: -------------------------------------------------------------------------------- 1 | time = 1.0 2 | height = 4.0 3 | 4 | # printf syntax (for comparison) 5 | print 'At t=%g s, y=%.2f m' % (time, height) 6 | 7 | # format string syntax 8 | print 'At t={t:g} s, y={y:.2f} m'.format(t=time, y=height) 9 | 10 | # format string syntax 11 | print 'At t={t:g} s, y={y:.2f} m'.format(y=height, t=time) 12 | -------------------------------------------------------------------------------- /py36-src/formatted_columns.py: -------------------------------------------------------------------------------- 1 | from math import sin 2 | 3 | t0 = 2 4 | dt = 0.55 5 | 6 | t = t0 + 0*dt; g = t*sin(t) 7 | print('{:6.2f} {:8.3f}'.format(t, g)) 8 | 9 | t = t0 + 1*dt; g = t*sin(t) 10 | print('{:6.2f} {:8.3f}'.format(t, g)) 11 | 12 | t = t0 + 2*dt; g = t*sin(t) 13 | print('{:6.2f} {:8.3f}'.format(t, g)) 14 | -------------------------------------------------------------------------------- /py36-src/formatted_print.py: -------------------------------------------------------------------------------- 1 | r = 12.89643 # real number 2 | i = 42 # integer 3 | s = 'some message' # string (equivalent: s = "some message") 4 | 5 | print('real={:.3f}, integer={:d}, string={:s}'.format(r, i, s)) 6 | print('real={:9.3e}, integer={:5d}, string={:s}'.format(r, i, s)) 7 | 8 | -------------------------------------------------------------------------------- /py36-src/function_as_argument.py: -------------------------------------------------------------------------------- 1 | def f(x): 2 | return x 3 | 4 | def g(x): 5 | return x**2 6 | 7 | def sum_function_values(f, start, stop): 8 | """Sum up function values for integer arguments as 9 | f(start) + f(start+1) + f(start+2) + ... + f(stop)""" 10 | S = 0 11 | for i in range(start, stop+1, 1): 12 | S = S + f(i) 13 | return S 14 | 15 | print('Sum with f becomes {:g}'.format(sum_function_values(f, 1, 3))) 16 | print('Sum with g becomes {:g}'.format(sum_function_values(g, 1, 3))) 17 | 18 | -------------------------------------------------------------------------------- /py36-src/growth1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | N_0 = int(input('Give initial population size N_0: ')) 5 | r = float(input('Give net growth rate r: ')) 6 | dt = float(input('Give time step size: ')) 7 | N_t = int(input('Give number of steps: ')) 8 | 9 | t = np.linspace(0, N_t*dt, N_t+1) 10 | N = np.zeros(N_t+1) 11 | 12 | N[0] = N_0 13 | for n in range(N_t): 14 | N[n+1] = N[n] + r*dt*N[n] 15 | 16 | numerical_sol = 'bo' if N_t < 70 else 'b-' 17 | plt.plot(t, N, numerical_sol, t, N_0*np.exp(r*t), 'r-') 18 | plt.legend(['numerical', 'exact'], loc='upper left') 19 | plt.xlabel('t'); plt.ylabel('N(t)') 20 | filestem = 'growth1_{:d}steps'.format(N_t) 21 | plt.savefig('{:s}.png'.format(filestem)) 22 | plt.savefig('{:s}.pdf'.format(filestem)) -------------------------------------------------------------------------------- /py36-src/integration_methods_vec.py: -------------------------------------------------------------------------------- 1 | from numpy import linspace, sum 2 | 3 | def midpoint(f, a, b, n): 4 | h = (b-a)/n 5 | x = linspace(a + h/2, b - h/2, n) 6 | return h*sum(f(x)) 7 | 8 | def trapezoidal(f, a, b, n): 9 | h = (b-a)/n 10 | x = linspace(a, b, n+1) 11 | s = sum(f(x)) - 0.5*f(a) - 0.5*f(b) 12 | return h*s 13 | -------------------------------------------------------------------------------- /py36-src/logistic.py: -------------------------------------------------------------------------------- 1 | from ode_FE import ode_FE 2 | import matplotlib.pyplot as plt 3 | 4 | for dt, T in zip((0.5, 20), (60, 100)): 5 | u, t = ode_FE(f=lambda u, t: 0.1*(1 - u/500.)*u, \ 6 | U_0=100, dt=dt, T=T) 7 | plt.figure() # Make separate figures for each pass in the loop 8 | plt.plot(t, u, 'b-') 9 | plt.xlabel('t'); plt.ylabel('N(t)') 10 | plt.savefig('tmp_{:g}.png'.format(dt)) 11 | plt.savefig('tmp_{:g}.pdf'.format(dt)) 12 | -------------------------------------------------------------------------------- /py36-src/midpoint.py: -------------------------------------------------------------------------------- 1 | def midpoint(f, a, b, n): 2 | h = (b-a)/n 3 | f_sum = 0 4 | for i in range(0, n, 1): 5 | x = (a + h/2.0) + i*h 6 | f_sum = f_sum + f(x) 7 | return h*f_sum 8 | 9 | def application(): 10 | from math import exp 11 | v = lambda t: 3*(t**2)*exp(t**3) 12 | n = int(input('n: ')) 13 | numerical = midpoint(v, 0, 1, n) 14 | 15 | # Compare with exact result 16 | V = lambda t: exp(t**3) 17 | exact = V(1) - V(0) 18 | error = abs(exact - numerical) 19 | print('n={:d}: {:.16f}, error: {:g}'.format(n, numerical, error)) 20 | 21 | if __name__ == '__main__': 22 | application() 23 | -------------------------------------------------------------------------------- /py36-src/midpoint_double.py: -------------------------------------------------------------------------------- 1 | def midpoint_double1(f, a, b, c, d, nx, ny): 2 | hx = (b - a)/nx 3 | hy = (d - c)/ny 4 | I = 0 5 | for i in range(nx): 6 | for j in range(ny): 7 | xi = a + hx/2 + i*hx 8 | yj = c + hy/2 + j*hy 9 | I = I + hx*hy*f(xi, yj) 10 | return I 11 | 12 | def midpoint(f, a, b, n): 13 | h = (b-a)/n 14 | f_sum = 0 15 | for i in range(0, n, 1): 16 | x = (a + h/2.0) + i*h 17 | f_sum = f_sum + f(x) 18 | return h*f_sum 19 | 20 | def midpoint_double2(f, a, b, c, d, nx, ny): 21 | def g(x): 22 | return midpoint(lambda y: f(x, y), c, d, ny) 23 | 24 | return midpoint(g, a, b, nx) 25 | 26 | def test_midpoint_double(): 27 | """Test that a linear function is integrated exactly.""" 28 | def f(x, y): 29 | return 2*x + y 30 | 31 | a = 0; b = 2; c = 2; d = 3 32 | import sympy 33 | x, y = sympy.symbols('x y') 34 | I_expected = sympy.integrate(f(x, y), (x, a, b), (y, c, d)) 35 | # Test three cases: nx < ny, nx = ny, nx > ny 36 | for nx, ny in (3, 5), (4, 4), (5, 3): 37 | I_computed1 = midpoint_double1(f, a, b, c, d, nx, ny) 38 | I_computed2 = midpoint_double2(f, a, b, c, d, nx, ny) 39 | tol = 1E-14 40 | #print I_expected, I_computed1, I_computed2 41 | assert abs(I_computed1 - I_expected) < tol 42 | assert abs(I_computed2 - I_expected) < tol 43 | 44 | if __name__ == '__main__': 45 | test_midpoint_double() 46 | -------------------------------------------------------------------------------- /py36-src/midpoint_triple.py: -------------------------------------------------------------------------------- 1 | def midpoint_triple1(g, a, b, c, d, e, f, nx, ny, nz): 2 | hx = (b - a)/nx 3 | hy = (d - c)/ny 4 | hz = (f - e)/nz 5 | I = 0 6 | for i in range(nx): 7 | for j in range(ny): 8 | for k in range(nz): 9 | xi = a + hx/2 + i*hx 10 | yj = c + hy/2 + j*hy 11 | zk = e + hz/2 + k*hz 12 | I = I + hx*hy*hz*g(xi, yj, zk) 13 | return I 14 | 15 | def midpoint(f, a, b, n): 16 | h = (b-a)/n 17 | f_sum = 0 18 | for i in range(0, n, 1): 19 | x = (a + h/2.0) + i*h 20 | f_sum = f_sum + f(x) 21 | return h*f_sum 22 | 23 | def midpoint_triple2(g, a, b, c, d, e, f, nx, ny, nz): 24 | def p(x, y): 25 | return midpoint(lambda z: g(x, y, z), e, f, nz) 26 | 27 | def q(x): 28 | return midpoint(lambda y: p(x, y), c, d, ny) 29 | 30 | return midpoint(q, a, b, nx) 31 | 32 | def test_midpoint_triple(): 33 | """Test that a linear function is integrated exactly.""" 34 | def g(x, y, z): 35 | return 2*x + y - 4*z 36 | 37 | a = 0; b = 2; c = 2; d = 3; e = -1; f = 2 38 | import sympy 39 | x, y, z = sympy.symbols('x y z') 40 | I_expected = sympy.integrate( 41 | g(x, y, z), (x, a, b), (y, c, d), (z, e, f)) 42 | for nx, ny, nz in (3, 5, 2), (4, 4, 4), (5, 3, 6): 43 | I_computed1 = midpoint_triple1( 44 | g, a, b, c, d, e, f, nx, ny, nz) 45 | I_computed2 = midpoint_triple2( 46 | g, a, b, c, d, e, f, nx, ny, nz) 47 | tol = 1E-14 48 | print(I_expected, I_computed1, I_computed2) 49 | assert abs(I_computed1 - I_expected) < tol 50 | assert abs(I_computed2 - I_expected) < tol 51 | 52 | if __name__ == '__main__': 53 | test_midpoint_triple() 54 | -------------------------------------------------------------------------------- /py36-src/naive_Newton.py: -------------------------------------------------------------------------------- 1 | def naive_Newton(f, dfdx, x, eps): 2 | while abs(f(x)) > eps: 3 | x = x - float(f(x))/dfdx(x) 4 | print(x) 5 | return x 6 | 7 | def app_sqrt(): 8 | def f(x): 9 | return x**2 - 9 10 | def dfdx(x): 11 | return 2*x 12 | print(naive_Newton(f, dfdx, 1000, 0.001)) 13 | 14 | if __name__ == '__main__': 15 | app_sqrt() 16 | 17 | -------------------------------------------------------------------------------- /py36-src/nonlinear_solvers.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def bisection(f, x_L, x_R, eps, return_x_list=False): 4 | f_L = f(x_L) 5 | if f_L*f(x_R) > 0: 6 | print("""Error! Function does not have opposite 7 | signs at interval endpoints!""") 8 | sys.exit(1) 9 | x_M = float(x_L + x_R)/2 10 | f_M = f(x_M) 11 | iteration_counter = 1 12 | if return_x_list: 13 | x_list = [] 14 | 15 | while abs(f_M) > eps: 16 | if f_L*f_M > 0: # i.e., same sign 17 | x_L = x_M 18 | f_L = f_M 19 | else: 20 | x_R = x_M 21 | x_M = float(x_L + x_R)/2 22 | f_M = f(x_M) 23 | iteration_counter += 1 24 | if return_x_list: 25 | x_list.append(x_M) 26 | if return_x_list: 27 | return x_list, iteration_counter 28 | else: 29 | return x_M, iteration_counter 30 | 31 | def Newton(f, dfdx, x, eps, return_x_list=False): 32 | f_value = f(x) 33 | iteration_counter = 0 34 | if return_x_list: 35 | x_list = [] 36 | 37 | while abs(f_value) > eps and iteration_counter < 100: 38 | try: 39 | x = x - float(f_value)/dfdx(x) 40 | except ZeroDivisionError: 41 | print('Error! - derivative zero for x = {:g}'.format(x)) 42 | sys.exit(1) # Abort with error 43 | 44 | f_value = f(x) 45 | iteration_counter += 1 46 | if return_x_list: 47 | x_list.append(x) 48 | 49 | # Here, either a solution is found, or too many iterations 50 | if abs(f_value) > eps: 51 | iteration_counter = -1 # i.e., lack of convergence 52 | 53 | if return_x_list: 54 | return x_list, iteration_counter 55 | else: 56 | return x, iteration_counter 57 | 58 | def secant(f, x0, x1, eps, return_x_list=False): 59 | f_x0 = f(x0) 60 | f_x1 = f(x1) 61 | iteration_counter = 0 62 | if return_x_list: 63 | x_list = [] 64 | 65 | while abs(f_x1) > eps and iteration_counter < 100: 66 | try: 67 | denominator = float(f_x1 - f_x0)/(x1 - x0) 68 | x = x1 - float(f_x1)/denominator 69 | except ZeroDivisionError: 70 | print('Error! - denominator zero for x = {:g}'.format(x)) 71 | sys.exit(1) # Abort with error 72 | x0 = x1 73 | x1 = x 74 | f_x0 = f_x1 75 | f_x1 = f(x1) 76 | iteration_counter += 1 77 | if return_x_list: 78 | x_list.append(x) 79 | # Here, either a solution is found, or too many iterations 80 | if abs(f_x1) > eps: 81 | iteration_counter = -1 82 | 83 | if return_x_list: 84 | return x_list, iteration_counter 85 | else: 86 | return x, iteration_counter 87 | 88 | from math import log 89 | 90 | def rate(x, x_exact): 91 | e = [abs(x_ - x_exact) for x_ in x] 92 | q = [log(e[n+1]/e[n])/log(e[n]/e[n-1]) 93 | for n in range(1, len(e)-1, 1)] 94 | return q 95 | -------------------------------------------------------------------------------- /py36-src/nonlinear_solvers_rates.py: -------------------------------------------------------------------------------- 1 | from nonlinear_solvers import bisection, Newton, secant, rate 2 | 3 | def f(x): 4 | return x**2 - 9 5 | 6 | def dfdx(x): 7 | return 2*x 8 | 9 | def print_rates(method, x, x_exact): 10 | q = ['%.2f' % q_ for q_ in rate(x, x_exact)] 11 | print method + ':' 12 | for q_ in q: 13 | print q_, 14 | print 15 | 16 | eps = 1e-6 17 | 18 | x, it = Newton(f, dfdx, 1000, eps, return_x_list=True) 19 | print_rates('Newton', x, 3) 20 | 21 | x0 = 1000; x1 = x0 - 1 22 | x, it = secant(f, x0, x1, eps, return_x_list=True) 23 | print_rates('Secant', x, 3) 24 | 25 | # The error model does not work well for Bisection when 26 | # the solution is approached 27 | x, it = bisection(f, 0, 1000, eps, return_x_list=True) 28 | print_rates('Bisection', x, 3) 29 | #e = [abs(x_-3) for x_ in x] 30 | #print [e[i+1]/e[i] for i in range(len(e)-1)] 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /py36-src/ode_FE.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def ode_FE(f, U_0, dt, T): 5 | N_t = int(round(T/dt)) 6 | u = np.zeros(N_t+1) 7 | t = np.linspace(0, N_t*dt, len(u)) 8 | u[0] = U_0 9 | for n in range(N_t): 10 | u[n+1] = u[n] + dt*f(u[n], t[n]) 11 | return u, t 12 | 13 | def demo_population_growth(): 14 | """Test case: u'=r*u, u(0)=100.""" 15 | def f(u, t): 16 | return 0.1*u 17 | 18 | u, t = ode_FE(f=f, U_0=100, dt=0.5, T=20) 19 | plt.plot(t, u, t, 100*np.exp(0.1*t)) 20 | plt.show() 21 | 22 | if __name__ == '__main__': 23 | demo_population_growth() 24 | -------------------------------------------------------------------------------- /py36-src/ode_system_FE.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def ode_FE(f, U_0, dt, T): 5 | N_t = int(round(T/dt)) 6 | # Ensure that any list/tuple returned from f_ is wrapped as array 7 | f_ = lambda u, t: np.asarray(f(u, t)) 8 | u = np.zeros((N_t+1, len(U_0))) 9 | t = np.linspace(0, N_t*dt, len(u)) 10 | u[0] = U_0 11 | for n in range(N_t): 12 | u[n+1] = u[n] + dt*f_(u[n], t[n]) 13 | return u, t 14 | 15 | def demo_SIR(): 16 | """Test case using a SIR model.""" 17 | def f(u, t): 18 | S, I, R = u 19 | return [-beta*S*I, beta*S*I - gamma*I, gamma*I] 20 | 21 | beta = 10./(40*8*24) 22 | gamma = 3./(15*24) 23 | dt = 0.1 # 6 min 24 | D = 30 # Simulate for D days 25 | N_t = int(D*24/dt) # Corresponding no of time steps 26 | T = dt*N_t # End time 27 | U_0 = [50, 1, 0] 28 | 29 | u, t = ode_FE(f, U_0, dt, T) 30 | 31 | S = u[:,0] 32 | I = u[:,1] 33 | R = u[:,2] 34 | fig = plt.figure() 35 | l1, l2, l3 = plt.plot(t, S, t, I, t, R) 36 | fig.legend((l1, l2, l3), ('S', 'I', 'R'), 'center right') 37 | plt.xlabel('hours') 38 | plt.show() 39 | 40 | # Consistency check: 41 | N = S[0] + I[0] + R[0] 42 | eps = 1E-12 # Tolerance for comparing real numbers 43 | for n in range(len(S)): 44 | SIR_sum = S[n] + I[n] + R[n] 45 | if abs(SIR_sum - N) > eps: 46 | print('*** consistency check failed: S+I+R={:g} != {:g}'\ 47 | .format(SIR_sum, N)) 48 | 49 | if __name__ == '__main__': 50 | demo_SIR() 51 | -------------------------------------------------------------------------------- /py36-src/osc_2nd_order.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def osc_2nd_order(U_0, omega, dt, T): 4 | """ 5 | Solve u'' + omega**2*u = 0 for t in (0,T], u(0)=U_0 and u'(0)=0, 6 | by a central finite difference method with time step dt. 7 | """ 8 | Nt = int(round(T/dt)) 9 | u = np.zeros(Nt+1) 10 | t = np.linspace(0, Nt*dt, Nt+1) 11 | 12 | u[0] = U_0 13 | u[1] = u[0] - 0.5*dt**2*omega**2*u[0] 14 | for n in range(1, Nt): 15 | u[n+1] = 2*u[n] - u[n-1] - dt**2*omega**2*u[n] 16 | return u, t 17 | -------------------------------------------------------------------------------- /py36-src/osc_EC.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | omega = 2 5 | P = 2*np.pi/omega 6 | dt = P/20 7 | T = 40*P 8 | T = P 9 | N_t = int(round(T/dt)) 10 | t = np.linspace(0, N_t*dt, N_t+1) 11 | print('N_t:', N_t) 12 | 13 | u = np.zeros(N_t+1) 14 | v = np.zeros(N_t+1) 15 | 16 | # Initial condition 17 | X_0 = 2 18 | u[0] = X_0 19 | v[0] = 0 20 | 21 | # Step equations forward in time 22 | for n in range(N_t): 23 | v[n+1] = v[n] - dt*omega**2*u[n] 24 | u[n+1] = u[n] + dt*v[n+1] 25 | 26 | # Plot the last four periods to illustrate the accuracy 27 | # in long time simulations 28 | N4l = int(round(4*P/dt)) # No of intervals to be plotted 29 | fig = plt.figure() 30 | l1, l2 = plt.plot(t[-N4l:], u[-N4l:], 'b-', 31 | t[-N4l:], X_0*np.cos(omega*t)[-N4l:], 'r--') 32 | fig.legend((l1, l2), ('numerical', 'exact'), 'upper left') 33 | plt.xlabel('t') 34 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 35 | plt.show() 36 | print('{:.16f} {:.16f}'.format(u[-1], v[-1])) -------------------------------------------------------------------------------- /py36-src/osc_EC_general.py: -------------------------------------------------------------------------------- 1 | from matplotlib.pyplot import plot, hold, legend, \ 2 | xlabel, ylabel, savefig, title, figure, show 3 | 4 | def EulerCromer(f, s, F, m, T, U_0, V_0, dt): 5 | import numpy as np 6 | N_t = int(round(T/dt)) 7 | print('N_t:', N_t) 8 | t = np.linspace(0, N_t*dt, N_t+1) 9 | 10 | u = np.zeros(N_t+1) 11 | v = np.zeros(N_t+1) 12 | 13 | # Initial condition 14 | u[0] = U_0 15 | v[0] = V_0 16 | 17 | # Step equations forward in time 18 | for n in range(N_t): 19 | v[n+1] = v[n] + dt*(1./m)*(F(t[n]) - f(v[n]) - s(u[n])) 20 | u[n+1] = u[n] + dt*v[n+1] 21 | return u, v, t 22 | 23 | def test_undamped_linear(): 24 | """Compare with data from osc_EC.py in a linear problem.""" 25 | import numpy as np 26 | omega = 2 27 | P = 2*np.pi/omega 28 | dt = P/20 29 | T = 40*P 30 | exact_v = -3.5035725322034139 31 | exact_u = 0.7283057044967003 32 | computed_u, computed_v, t = EulerCromer( 33 | f=lambda v: 0, s=lambda u: omega**2*u, 34 | F=lambda t: 0, m=1, T=T, U_0=2, V_0=0, dt=dt) 35 | diff_u = abs(exact_u - computed_u[-1]) 36 | diff_v = abs(exact_v - computed_v[-1]) 37 | tol = 1E-14 38 | assert diff_u < tol and diff_v < tol 39 | 40 | def _test_manufactured_solution(damping=True): 41 | import sympy as sp 42 | t, m, k, b = sp.symbols('t m k b') 43 | # Choose solution 44 | u = sp.sin(t) 45 | v = sp.diff(u, t) 46 | # Choose f, s, F 47 | f = b*v 48 | s = k*sp.tanh(u) 49 | F = sp.cos(2*t) 50 | 51 | equation = m*sp.diff(v, t) + f + s - F 52 | 53 | # Adjust F (source term because of manufactured solution) 54 | F += equation 55 | print('F:', F) 56 | 57 | # Set values for the symbols m, b, k 58 | m = 0.5 59 | k = 1.5 60 | b = 0.5 if damping else 0 61 | F = F.subs('m', m).subs('b', b).subs('k', k) 62 | 63 | print(f, s, F) 64 | # Turn sympy expression into Python function 65 | F = sp.lambdify([t], F) 66 | # Define Python functions for f and s 67 | # (the expressions above are functions of t, we need 68 | # s(u) and f(v) 69 | from numpy import tanh 70 | s = lambda u: k*tanh(u) 71 | f = lambda v: b*v 72 | 73 | # Add modules='numpy' such that exact u and v work 74 | # with t as array argument 75 | exact_u = sp.lambdify([t], u, modules='numpy') 76 | exact_v = sp.lambdify([t], v, modules='numpy') 77 | 78 | 79 | # Solve problem for different dt 80 | from numpy import pi, sqrt, sum, log 81 | P = 2*pi 82 | time_intervals_per_period = [20, 40, 80, 160, 240] 83 | h = [] # store discretization parameters 84 | E_u = [] # store errors in u 85 | E_v = [] # store errors in v 86 | 87 | for n in time_intervals_per_period: 88 | dt = P/n 89 | T = 8*P 90 | computed_u, computed_v, t = EulerCromer( 91 | f=f, s=s, F=F, m=m, T=T, 92 | U_0=exact_u(0), V_0=exact_v(0), dt=dt) 93 | 94 | error_u = sqrt(dt*sum((exact_u(t) - computed_u)**2)) 95 | error_v = sqrt(dt*sum((exact_v(t) - computed_v)**2)) 96 | h.append(dt) 97 | E_u.append(error_u) 98 | E_v.append(error_v) 99 | 100 | """ 101 | # Compare exact and computed curves for this resolution 102 | figure() 103 | plot_u(computed_u, t, show=False) 104 | hold('on') 105 | plot(t, exact_u(t), show=True) 106 | legend(['numerical', 'exact']) 107 | savefig('tmp_%d.pdf' % n); savefig('tmp_%d.png' % n) 108 | """ 109 | # Compute convergence rates 110 | r_u = [log(E_u[i]/E_u[i-1])/log(h[i]/h[i-1]) 111 | for i in range(1, len(h))] 112 | r_v = [log(E_u[i]/E_u[i-1])/log(h[i]/h[i-1]) 113 | for i in range(1, len(h))] 114 | tol = 0.02 115 | exact_r_u = 1.0 if damping else 2.0 116 | exact_r_v = 1.0 if damping else 2.0 117 | success = abs(exact_r_u - r_u[-1]) < tol and \ 118 | abs(exact_r_v - r_v[-1]) < tol 119 | msg = ' u rate: {:.2f}, v rate: {:.2f}'.format(r_u[-1], r_v[-1]) 120 | assert success, msg 121 | 122 | def test_manufactured_solution(): 123 | _test_manufactured_solution(damping=True) 124 | _test_manufactured_solution(damping=False) 125 | 126 | # Plot the a percentage of the time series, up to the end, to 127 | # illustrate the accuracy in long time simulations 128 | def plot_u(u, t, percentage=100, show_plot=True, heading='', labels=('t', 'u')): 129 | index = int(len(u)*percentage/100) 130 | plot(t[-index:], u[-index:], 'b-') 131 | xlabel(labels[0]); ylabel(labels[1]) 132 | title(heading) 133 | savefig('tmp.pdf'); savefig('tmp.png') 134 | if show_plot: 135 | show() 136 | 137 | def linear_damping(): 138 | import numpy as np 139 | b = 0.3 140 | f = lambda v: b*v 141 | s = lambda u: k*u 142 | F = lambda t: 0 143 | 144 | m = 1 145 | k = 1 146 | U_0 = 1 147 | V_0 = 0 148 | 149 | T = 12*np.pi 150 | dt = T/5000. 151 | 152 | u, v, t = EulerCromer(f=f, s=s, F=F, m=m, T=T, 153 | U_0=U_0, V_0=V_0, dt=dt) 154 | plot_u(u, t) 155 | 156 | def linear_damping_sine_excitation(): 157 | b = 0.3 158 | f = lambda v: b*v 159 | s = lambda u: k*u 160 | import math 161 | w = 3 162 | A = 0.5 163 | F = lambda t: A*math.sin(w*t) 164 | 165 | m = 1 166 | k = 1 167 | U_0 = 1 168 | V_0 = 0 169 | 170 | T = 12*math.pi 171 | dt = T/5000. 172 | 173 | u, v, t = EulerCromer(f=f, s=s, F=F, m=m, T=T, 174 | U_0=U_0, V_0=V_0, dt=dt) 175 | plot_u(u, t) 176 | 177 | def sliding_friction(): 178 | from numpy import tanh, sign 179 | 180 | f = lambda v: mu*m*g*sign(v) 181 | alpha = 60.0 182 | s = lambda u: k/alpha*tanh(alpha*u) 183 | F = lambda t: 0 184 | 185 | g = 9.81 186 | mu = 0.4 187 | m = 1 188 | k = 1000 189 | 190 | U_0 = 0.1 191 | V_0 = 0 192 | 193 | T = 2 194 | dt = T/5000. 195 | 196 | u, v, t = EulerCromer(f=f, s=s, F=F, m=m, T=T, 197 | U_0=U_0, V_0=V_0, dt=dt) 198 | plot_u(u, t) 199 | 200 | if __name__ == '__main__': 201 | #linear_damping() 202 | #test_undamped_linear() 203 | #test_manufactured_solution() 204 | #sliding_friction() 205 | linear_damping_sine_excitation() 206 | -------------------------------------------------------------------------------- /py36-src/osc_FE.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | omega = 2 5 | P = 2*np.pi/omega 6 | dt = P/20 7 | T = 3*P 8 | N_t = int(round(T/dt)) 9 | t = np.linspace(0, N_t*dt, N_t+1) 10 | 11 | u = np.zeros(N_t+1) 12 | v = np.zeros(N_t+1) 13 | 14 | # Initial condition 15 | X_0 = 2 16 | u[0] = X_0 17 | v[0] = 0 18 | 19 | # Step equations forward in time 20 | for n in range(N_t): 21 | u[n+1] = u[n] + dt*v[n] 22 | v[n+1] = v[n] - dt*omega**2*u[n] 23 | 24 | fig = plt.figure() 25 | l1, l2 = plt.plot(t, u, 'b-', t, X_0*np.cos(omega*t), 'r--') 26 | fig.legend((l1, l2), ('numerical', 'exact'), 'upper right') 27 | plt.xlabel('t') 28 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 29 | plt.show() 30 | 31 | # Exact analytical solution 32 | plt.figure() 33 | u_num_ex = np.array([X_0*(1+1j*omega*dt)**n for n in range(N_t+1)]) 34 | plt.plot(t, u, 'b-', t, u_num_ex.real, 'r-') 35 | plt.show() 36 | -------------------------------------------------------------------------------- /py36-src/osc_Heun.py: -------------------------------------------------------------------------------- 1 | #from numpy import zeros, linspace, pi, cos 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | def osc_Heun(X_0, omega, dt, T): 6 | N_t = int(round(T/dt)) 7 | u = np.zeros(N_t+1) 8 | v = np.zeros(N_t+1) 9 | t = np.linspace(0, N_t*dt, N_t+1) 10 | 11 | # Initial condition 12 | u[0] = X_0 13 | v[0] = 0 14 | 15 | # Step equations forward in time 16 | for n in range(N_t): 17 | u_star = u[n] + dt*v[n] 18 | v_star = v[n] - dt*omega**2*u[n] 19 | u[n+1] = u[n] + 0.5*dt*(v[n] + v_star) 20 | v[n+1] = v[n] - 0.5*dt*omega**2*(u[n] + u_star) 21 | return u, v, t 22 | 23 | def demo(): 24 | omega = 2 25 | P = 2*np.pi/omega 26 | dt = P/20 27 | T = 10*P 28 | X_0 = 2 29 | u, v, t = osc_Heun(X_0, omega, dt, T) 30 | 31 | fig = plt.figure() 32 | l1, l2 = plt.plot(t, u, 'b-', t, X_0*np.cos(omega*t), 'r--') 33 | fig.legend((l1, l2), ('numerical', 'exact'), 'upper left') 34 | plt.xlabel('t') 35 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 36 | plt.show() 37 | 38 | if __name__ == '__main__': 39 | demo() 40 | -------------------------------------------------------------------------------- /py36-src/osc_RK4.py: -------------------------------------------------------------------------------- 1 | # Just use odespy... 2 | 3 | import odespy 4 | import matplotlib.pyplot as plt 5 | 6 | def f(u, t, omega=2): 7 | u, v = u 8 | return [v, -omega**2*u] 9 | 10 | def demo(): 11 | from numpy import pi, linspace, cos 12 | omega = 2 13 | P = 2*pi/omega 14 | dt = P/20 15 | T = 40*P 16 | X_0 = 2 17 | RK4 = odespy.RK4(f, f_args=[omega]) 18 | RK4.set_initial_condition([X_0, 0]) 19 | N_t = int(round(T/dt)) 20 | u, t = RK4.solve(linspace(0, T, N_t+1)) 21 | u, v = u[:,0], u[:,1] 22 | 23 | # Last p periods 24 | p = 10 25 | m = p*20 26 | fig = plt.figure() 27 | l1, l2 = plt.plot(t[-m:], u[-m:], 'b-', t[-m:], X_0*cos(omega*t)[-m:], 'r--') 28 | fig.legend((l1, l2), ('numerical', 'exact'), 'lower left') 29 | plt.xlabel('t') 30 | plt.show() 31 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 32 | 33 | demo() 34 | -------------------------------------------------------------------------------- /py36-src/osc_odespy.py: -------------------------------------------------------------------------------- 1 | """Use odespy to solve undamped oscillation ODEs.""" 2 | 3 | import odespy 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | 7 | def f(u, t, omega=2): 8 | v, u = u 9 | return [-omega**2*u, v] 10 | 11 | def compare(odespy_methods, 12 | omega, 13 | X_0, 14 | number_of_periods, 15 | time_intervals_per_period=20): 16 | 17 | P = 2*np.pi/omega # length of one period 18 | dt = P/time_intervals_per_period 19 | T = number_of_periods*P 20 | 21 | # If odespy_methods is not a list, but just the name of 22 | # a single Odespy solver, we wrap that name in a list 23 | # so we always have odespy_methods as a list 24 | if type(odespy_methods) != type([]): 25 | odespy_methods = [odespy_methods] 26 | 27 | # Make a list of solver objects 28 | solvers = [method(f, f_args=[omega]) for method in 29 | odespy_methods] 30 | for solver in solvers: 31 | solver.set_initial_condition([0, X_0]) 32 | 33 | # Compute the time points where we want the solution 34 | N_t = int(round(T/dt)) 35 | time_points = np.linspace(0, N_t*dt, N_t+1) 36 | 37 | legends = [] 38 | for solver in solvers: 39 | sol, t = solver.solve(time_points) 40 | v = sol[:,0] 41 | u = sol[:,1] 42 | 43 | # Plot only the last p periods 44 | p = 6 45 | m = p*time_intervals_per_period # no time steps to plot 46 | plt.plot(t[-m:], u[-m:]) 47 | plt.hold('on') 48 | legends.append(solver.name()) 49 | plt.xlabel('t') 50 | # Plot exact solution too 51 | plt.plot(t[-m:], X_0*np.cos(omega*t)[-m:], 'k--') 52 | legends.append('exact') 53 | plt.legend(legends, loc='lower left') 54 | plt.axis([t[-m], t[-1], -2*X_0, 2*X_0]) 55 | plt.title('Simulation of {:d} periods with {:d} intervals per period'\ 56 | .format(number_of_periods, time_intervals_per_period)) 57 | plt.savefig('tmp.pdf'); plt.savefig('tmp.png') 58 | plt.show() 59 | 60 | # some relevant methods to use when calling campare: odespy.Heun, 61 | # odespy.EulerCromer, odespy.BackwardEuler, odespy.RKFehlberg, 62 | 63 | #compare(odespy_methods=[odespy.Heun, odespy.EulerCromer ], 64 | # omega=2, X_0=2, number_of_periods=20, 65 | # time_intervals_per_period=20) 66 | 67 | #compare(odespy_methods=[odespy.EulerCromer, odespy.RKFehlberg ], 68 | # omega=2, X_0=2, number_of_periods=200, 69 | # time_intervals_per_period=40) 70 | 71 | #compare(odespy_methods=[odespy.RK4], 72 | # omega=2, X_0=2, number_of_periods=200, 73 | # time_intervals_per_period=40) 74 | 75 | compare(odespy_methods=[odespy.EulerCromer, odespy.BackwardEuler], 76 | omega=2, X_0=2,number_of_periods=6, 77 | time_intervals_per_period=60) 78 | -------------------------------------------------------------------------------- /py36-src/osc_odespy_general.py: -------------------------------------------------------------------------------- 1 | """Use odespy to solve general oscillation ODEs.""" 2 | 3 | import odespy 4 | from matplotlib.pyplot import \ 5 | plot, savefig, legend, xlabel, figure, title, hold, axis, show 6 | 7 | def compare(odespy_methods, f, s, F, m, U_0, V_0, T, dt, 8 | start_of_plot=0, umin=None, umax=None, 9 | exact_solution=None): 10 | from numpy import linspace, zeros 11 | 12 | def rhs(sol, t, m, f, s, F): 13 | # This function will remember the variables in the compare 14 | # function, such as m, F, s, and f, even when called from 15 | # odespy 16 | v, u = sol 17 | return [(1./m)*(F(t) - s(u) - f(v)), 18 | v] 19 | 20 | # If odespy_methods is not a list, but just the name of 21 | # a single Odespy solver, we wrap that name in a list 22 | # so we always have odespy_methods as a list 23 | if type(odespy_methods) != type([]): 24 | odespy_methods = [odespy_methods] 25 | 26 | # Make a list of solver objects 27 | solvers = [method(rhs, f_args=[m, f, s, F]) for method in 28 | odespy_methods] 29 | for solver in solvers: 30 | solver.set_initial_condition([V_0, U_0]) 31 | 32 | # Compute the time points where we want the solution 33 | dt = float(dt) # avoid integer division 34 | N_t = int(round(T/dt)) 35 | time_points = linspace(0, N_t*dt, N_t+1) 36 | 37 | # Convert start_of_plot to index m: m*dt = start_of_plot 38 | m = int(round(start_of_plot/dt)) 39 | 40 | legends = [] 41 | for solver in solvers: 42 | sol, t = solver.solve(time_points) 43 | v = sol[:,0] 44 | u = sol[:,1] 45 | 46 | if len(solvers) == 1: 47 | plot(t[m:], u[m:], 'b-') # blue line without markers 48 | else: 49 | plot(t[m:], u[m:]) # automatic line marker/color 50 | hold('on') 51 | legends.append(solver.name()) 52 | xlabel('t') 53 | # Plot exact solution if available 54 | if exact_solution: 55 | plot(t[m:], exact_solution(t[m:]), 'k--') 56 | legends.append('exact') 57 | legend(legends, loc='lower left') 58 | if umin is not None and umax is not None: 59 | axis([t[m:], t[-1], umin, umax]) 60 | savefig('tmp.pdf'); savefig('tmp.png') 61 | show() 62 | 63 | def undamped_linear(): 64 | omega = 2 65 | number_of_periods = 60 66 | time_intervals_per_period = 20 67 | 68 | from numpy import pi, linspace, cos 69 | P = 2*pi/omega # length of one period 70 | dt = P/time_intervals_per_period 71 | T = number_of_periods*P 72 | 73 | methods = [odespy.EulerCromer] 74 | X_0 = 2 75 | compare(methods, 76 | f=lambda v: 0, 77 | s=lambda u: omega**2*u, 78 | F=lambda t: 0, 79 | m=1, U_0=X_0, V_0=0, T=T, dt=dt, 80 | start_of_plot=T-6*P, 81 | umin=-2*X_0, umax=2*X_0, 82 | exact_solution=lambda t: X_0*cos(omega*t)) 83 | 84 | def sliding_friction(): 85 | from numpy import tanh, sign 86 | 87 | f = lambda v: mu*m*g*sign(v) 88 | alpha = 60.0 89 | s = lambda u: k/alpha*tanh(alpha*u) 90 | #s = lambda u: k*u 91 | F = lambda t: 0 92 | 93 | g = 9.81 94 | mu = 0.4 95 | m = 1 96 | k = 1000 97 | 98 | U_0 = 0.1 99 | V_0 = 0 100 | 101 | T = 1 102 | dt = T/5000. 103 | 104 | methods = [odespy.EulerCromer, odespy.ForwardEuler] 105 | compare(methods, f=f, s=s, F=F, m=1, U_0=U_0, V_0=V_0, 106 | T=T, dt=dt, start_of_plot=0) 107 | 108 | #undamped_linear() 109 | sliding_friction() 110 | -------------------------------------------------------------------------------- /py36-src/plot_multiple_curves.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | t = np.linspace(-2, 2, 100) # choose 100 points in time interval 5 | 6 | f_values = t**2 7 | g_values = np.exp(t) 8 | 9 | plt.plot(t, f_values, 'r', t, g_values, 'b--') 10 | plt.xlabel('t') 11 | plt.ylabel('f and g') 12 | plt.legend(['t**2', 'e**t']) 13 | plt.title('Plotting of two functions (t**2 and e**t)') 14 | plt.grid('on') 15 | plt.axis([-3, 3, -1, 10]) 16 | plt.show() -------------------------------------------------------------------------------- /py36-src/print_columns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from math import sin 4 | 5 | t0 = 2 6 | dt = 0.55 7 | 8 | t = t0 + 0*dt; g = t*sin(t) 9 | print('{:6.2f} {:8.3f}'.format(t, g)) 10 | 11 | t = t0 + 1*dt; g = t*sin(t) 12 | print('{:6.2f} {:8.3f}'.format(t, g)) 13 | 14 | t = t0 + 2*dt; g = t*sin(t) 15 | print('{:6.2f} {:8.3f}'.format(t, g)) 16 | 17 | print("""hei1 18 | hei2 {} 19 | hei3 {} hei4 20 | yes!""".format(t, g)) -------------------------------------------------------------------------------- /py36-src/print_rates.py: -------------------------------------------------------------------------------- 1 | from nonlinear_solvers import rate 2 | 3 | def print_rates(method, x, x_exact): 4 | q = ['{:.2f}'.format(q_) for q_ in rate(x, x_exact)] 5 | print(method + ':') 6 | for q_ in q: 7 | print(q_, " ", end="") # end="" suppresses newline 8 | 9 | if __name__ == '__main__': 10 | print_rates('Newton', x = [1, 2, 3, 4, 5], x_exact = 3) 11 | -------------------------------------------------------------------------------- /py36-src/random_walk_2D.py: -------------------------------------------------------------------------------- 1 | import random 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | N = 1000 # number of steps 6 | d = 1 # step length (e.g., in meter) 7 | x = np.zeros(N+1) # x coordinates 8 | y = np.zeros(N+1) # y coordinates 9 | x[0] = 0; y[0] = 0 # set initial position 10 | 11 | for i in range(0, N, 1): 12 | r = random.random() # random number in [0,1) 13 | if 0 <= r < 0.25: # move north 14 | y[i+1] = y[i] + d 15 | x[i+1] = x[i] 16 | elif 0.25 <= r < 0.5: # move east 17 | x[i+1] = x[i] + d 18 | y[i+1] = y[i] 19 | elif 0.5 <= r < 0.75: # move south 20 | y[i+1] = y[i] - d 21 | x[i+1] = x[i] 22 | else: # move west 23 | x[i+1] = x[i] - d 24 | y[i+1] = y[i] 25 | 26 | # plot path (mark start and stop with blue o and *, respectively) 27 | plt.plot(x, y, 'r--', x[0], y[0], 'bo', x[-1], y[-1], 'b*') 28 | plt.xlabel('x'); plt.ylabel('y') 29 | plt.show() 30 | -------------------------------------------------------------------------------- /py36-src/rate_exponential.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | a = 0.0; b = 3.0 # time interval 5 | N = 30 # number of time steps 6 | dt = (b - a)/N # time step (s) 7 | V = np.zeros(N+1) # numerically computed volume (L) 8 | V[0] = 1 # inital volume 9 | 10 | for i in range(0, N, 1): 11 | V[i+1] = V[i] + dt*V[i] # ...r is V now 12 | 13 | time_exact = np.linspace(a, b, 1000) 14 | V_exact = np.exp(time_exact) # make exact solution (for plotting) 15 | time = np.linspace(0, 3, N+1) 16 | plt.plot(time, V, 'bo-', time_exact, V_exact, 'r') 17 | plt.title('Case 2') 18 | plt.legend(['numerical','exact'], loc='upper left') 19 | plt.xlabel('t (s)') 20 | plt.ylabel('V (L)') 21 | plt.show() -------------------------------------------------------------------------------- /py36-src/rate_piecewise_constant.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | a = 0.0; b = 3.0 # time interval 5 | N = 3 # number of time steps 6 | dt = (b - a)/N # time step (s) 7 | V_exact = [1.0, 2.0, 5.0, 12.0] # exact volumes (L) 8 | V = np.zeros(4) # numerically computed volume (L) 9 | V[0] = 1 # inital volume 10 | r = np.zeros(3) # rates of volume increase (L/s) 11 | r[0] = 1; r[1] = 3; r[2] = 7 12 | 13 | for i in [0, 1, 2]: 14 | V[i+1] = V[i] + dt*r[i] 15 | 16 | time = [0, 1, 2, 3] 17 | plt.plot(time, V, 'bo-', time, V_exact, 'r') 18 | plt.title('Case 1') 19 | plt.legend(['numerical','exact'], loc='upper left') 20 | plt.xlabel('t (s)') 21 | plt.ylabel('V (L)') 22 | plt.show() 23 | -------------------------------------------------------------------------------- /py36-src/rod_BE.py: -------------------------------------------------------------------------------- 1 | """Temperature evolution in a rod, computed by a BackwardEuler method.""" 2 | 3 | from numpy import linspace, zeros, linspace 4 | 5 | def rhs(u, t): 6 | N = len(u) - 1 7 | rhs = zeros(N+1) 8 | rhs[0] = dsdt(t) 9 | for i in range(1, N): 10 | rhs[i] = (beta/dx**2)*(u[i+1] - 2*u[i] + u[i-1]) + \ 11 | g(x[i], t) 12 | rhs[N] = (beta/dx**2)*(2*u[i-1] + 2*dx*dudx(t) - 13 | 2*u[i]) + g(x[N], t) 14 | return rhs 15 | 16 | def K(u, t): 17 | N = len(u) - 1 18 | K = zeros((N+1,N+1)) 19 | K[0,0] = 0 20 | for i in range(1, N): 21 | K[i,i-1] = beta/dx**2 22 | K[i,i] = -2*beta/dx**2 23 | K[i,i+1] = beta/dx**2 24 | K[N,N-1] = (beta/dx**2)*2 25 | K[N,N] = (beta/dx**2)*(-2) 26 | return K 27 | 28 | def rhs_vec(u, t): 29 | N = len(u) - 1 30 | rhs = zeros(N+1) 31 | rhs[0] = dsdt(t) 32 | rhs[1:N] = (beta/dx**2)*(u[2:N+1] - 2*u[1:N] + u[0:N-1]) + \ 33 | g(x[1:N], t) 34 | i = N 35 | rhs[i] = (beta/dx**2)*(2*u[i-1] + 2*dx*dudx(t) - 36 | 2*u[i]) + g(x[N], t) 37 | return rhs 38 | 39 | def K_vec(u, t): 40 | """Vectorized computation of K.""" 41 | N = len(u) - 1 42 | K = zeros((N+1,N+1)) 43 | K[0,0] = 0 44 | K[1:N-1] = beta/dx**2 45 | K[1:N] = -2*beta/dx**2 46 | K[2:N+1] = beta/dx**2 47 | K[N,N-1] = (beta/dx**2)*2 48 | K[N,N] = (beta/dx**2)*(-2) 49 | return K 50 | 51 | def dudx(t): 52 | return 0 53 | 54 | def s(t): 55 | return 323 56 | 57 | def dsdt(t): 58 | return 0 59 | 60 | def g(x, t): 61 | return 0 62 | 63 | L = 0.5 64 | beta = 8.2E-5 65 | N = 40 66 | x = linspace(0, L, N+1) 67 | dx = x[1] - x[0] 68 | u = zeros(N+1) 69 | 70 | U_0 = zeros(N+1) 71 | U_0[0] = s(0) 72 | U_0[1:] = 283 73 | dt = dx**2/(2*beta) 74 | print('stability limit:', dt) 75 | dt = 600 # 10 min 76 | 77 | import odespy 78 | solver = odespy.BackwardEuler(rhs, f_is_linear=True, jac=K) 79 | solver = odespy.ThetaRule(rhs, f_is_linear=True, jac=K, theta=0.5) 80 | solver.set_initial_condition(U_0) 81 | T = 1*60*60 82 | N_t = int(round(T/dt)) 83 | time_points = linspace(0, T, N_t+1) 84 | u, t = solver.solve(time_points) 85 | 86 | # Make movie 87 | import os 88 | os.system('rm tmp_*.png') 89 | import matplotlib.pyplot as plt 90 | import time 91 | plt.ion() 92 | y = u[0,:] 93 | lines = plt.plot(x, y) 94 | plt.axis([x[0], x[-1], 273, s(0)+10]) 95 | plt.xlabel('x') 96 | plt.ylabel('u(x,t)') 97 | counter = 0 98 | for i in range(0, u.shape[0]): 99 | print(t[i]) 100 | lines[0].set_ydata(u[i,:]) 101 | plt.legend(['t=%.0f' % t[i]]) 102 | plt.draw() 103 | plt.savefig('tmp_%04d.png' % counter) 104 | counter += 1 105 | time.sleep(0.2) 106 | -------------------------------------------------------------------------------- /py36-src/rod_FE.py: -------------------------------------------------------------------------------- 1 | """Temperature evolution in a rod, computed by a ForwardEuler method.""" 2 | 3 | import numpy as np 4 | 5 | def rhs(u, t): 6 | N = len(u) - 1 7 | rhs = np.zeros(N+1) 8 | rhs[0] = dsdt(t) 9 | for i in range(1, N): 10 | rhs[i] = (beta/dx**2)*(u[i+1] - 2*u[i] + u[i-1]) + \ 11 | g(x[i], t) 12 | i = N 13 | rhs[i] = (beta/dx**2)*(2*u[i-1] + 2*dx*dudx(t) - 14 | 2*u[i]) + g(x[N], t) 15 | return rhs 16 | 17 | def dudx(t): 18 | return 0 19 | 20 | def s(t): 21 | return 323 22 | 23 | def dsdt(t): 24 | return 0 25 | 26 | def g(x, t): 27 | return 0 28 | 29 | 30 | L = 0.5 31 | beta = 8.2E-5 32 | N = 40 33 | x = np.linspace(0, L, N+1) 34 | dx = x[1] - x[0] 35 | u = np.zeros(N+1) 36 | 37 | U_0 = np.zeros(N+1) 38 | U_0[0] = s(0) 39 | U_0[1:] = 283 40 | dt = dx**2/(2*beta) 41 | print('stability limit:', dt) 42 | #dt = 0.00034375 43 | 44 | from ode_system_FE import ode_FE 45 | u, t = ode_FE(rhs, U_0, dt, T=1*60*60) 46 | 47 | # Make movie 48 | import os 49 | os.system('rm tmp_*.png') 50 | import matplotlib.pyplot as plt 51 | plt.ion() 52 | y = u[0,:] 53 | lines = plt.plot(x, y) 54 | plt.axis([x[0], x[-1], 273, s(0)+10]) 55 | plt.xlabel('x') 56 | plt.ylabel('u(x,t)') 57 | counter = 0 58 | # Plot each of the first 100 frames, then increase speed by 10x 59 | change_speed = 100 60 | for i in range(0, u.shape[0]): 61 | print(t[i]) 62 | plot = True if i <= change_speed else i % 10 == 0 63 | lines[0].set_ydata(u[i,:]) 64 | if i > change_speed: 65 | plt.legend(['t={:.0f} 10x'.format(t[i])]) 66 | else: 67 | plt.legend(['t={:.0f}'.format(t[i])]) 68 | plt.draw() 69 | if plot: 70 | plt.savefig('tmp_{:04d}.png'.format(counter)) 71 | counter += 1 72 | #time.sleep(0.2) 73 | -------------------------------------------------------------------------------- /py36-src/rod_FE_scaled.py: -------------------------------------------------------------------------------- 1 | """Temperature evolution in a rod, computed by a ForwardEuler method.""" 2 | # As rod_FE.py, but here physical parameters are set for the 3 | # scaled problem. 4 | 5 | from numpy import linspace, zeros, linspace 6 | import time 7 | 8 | def rhs(u, t): 9 | N = len(u) - 1 10 | rhs = zeros(N+1) 11 | rhs[0] = dsdt(t) 12 | for i in range(1, N): 13 | rhs[i] = (beta/dx**2)*(u[i+1] - 2*u[i] + u[i-1]) + \ 14 | f(x[i], t) 15 | i = N 16 | rhs[i] = (beta/dx**2)*(2*u[i-1] + 2*dx*dudx(t) - 17 | 2*u[i]) + f(x[N], t) 18 | return rhs 19 | 20 | def dudx(t): 21 | return 0 22 | 23 | def s(t): 24 | return 1 25 | 26 | def dsdt(t): 27 | return 0 28 | 29 | def f(x, t): 30 | return 0 31 | 32 | 33 | L = 1 34 | beta = 1 35 | N = 40 36 | x = linspace(0, L, N+1) 37 | dx = x[1] - x[0] 38 | u = zeros(N+1) 39 | 40 | U_0 = zeros(N+1) 41 | U_0[0] = s(0) 42 | U_0[1:] = 0 43 | dt = dx**2/(2*beta) 44 | print 'stability limit:', dt 45 | 46 | t0 = time.clock() 47 | from ode_system_FE import ode_FE 48 | u, t = ode_FE(rhs, U_0, dt, T=1.2) 49 | t1 = time.clock() 50 | print 'CPU time: %.1fs' % (t1 - t0) 51 | 52 | # Make movie 53 | import os 54 | os.system('rm tmp_*.png') 55 | import matplotlib.pyplot as plt 56 | plt.ion() 57 | y = u[0,:] 58 | lines = plt.plot(x, y) 59 | plt.axis([x[0], x[-1], -0.1, 1.2*s(0)]) 60 | plt.xlabel('x') 61 | plt.ylabel('u(x,t)') 62 | counter = 0 63 | # Plot each of the first 100 frames, then increase speed by 10x 64 | change_speed = 100 65 | for i in range(0, u.shape[0]): 66 | print t[i] 67 | plot = True if i <= change_speed else i % 10 == 0 68 | lines[0].set_ydata(u[i,:]) 69 | if i > change_speed: 70 | plt.legend(['t=%.3f 10x' % t[i]]) 71 | else: 72 | plt.legend(['t=%.3f' % t[i]]) 73 | plt.draw() 74 | if plot: 75 | plt.savefig('tmp_%04d.png' % counter) 76 | counter += 1 77 | #time.sleep(0.2) 78 | -------------------------------------------------------------------------------- /py36-src/rod_FE_vec.py: -------------------------------------------------------------------------------- 1 | """Temperature evolution in a rod, computed by a ForwardEuler method.""" 2 | 3 | from numpy import linspace, zeros, linspace 4 | 5 | def rhs(u, t): 6 | N = len(u) - 1 7 | rhs = zeros(N+1) 8 | rhs[0] = dsdt(t) 9 | rhs[1:N] = (beta/dx**2)*(u[2:N+1] - 2*u[1:N] + u[0:N-1]) + \ 10 | g(x[1:N], t) 11 | i = N 12 | rhs[i] = (beta/dx**2)*(2*u[i-1] + 2*dx*dudx(t) - 13 | 2*u[i]) + g(x[i], t) 14 | return rhs 15 | 16 | def dudx(t): 17 | return 0 18 | 19 | def s(t): 20 | return 423 21 | 22 | def dsdt(t): 23 | return 0 24 | 25 | def g(x, t): 26 | return 0 27 | 28 | 29 | L = 1 30 | beta = 1 31 | N = 100 32 | x = linspace(0, L, N+1) 33 | dx = x[1] - x[0] 34 | u = zeros(N+1) 35 | 36 | U_0 = zeros(N+1) 37 | U_0[0] = s(0) 38 | U_0[1:] = 283 39 | dt = dx**2/(2*beta) 40 | print('stability limit:', dt) 41 | #dt = 0.00034375 42 | 43 | from ode_system_FE import ode_FE 44 | u, t = ode_FE(rhs, U_0, dt, T=1.2) 45 | import sys; sys.exit(0) 46 | 47 | # Make movie 48 | import os 49 | os.system('rm tmp_*.png') 50 | import matplotlib.pyplot as plt 51 | plt.ion() 52 | y = u[0,:] 53 | lines = plt.plot(x, y) 54 | plt.axis([x[0], x[-1], 273, 1.2*s(0)]) 55 | plt.xlabel('x') 56 | plt.ylabel('u(x,t)') 57 | counter = 0 58 | for i in range(0, u.shape[0]): 59 | print(t[i]) 60 | lines[0].set_ydata(u[i,:]) 61 | plt.legend(['t={:.3f}'.format(t[i])]) 62 | plt.draw() 63 | if i % 10 == 0: # plot every x steps 64 | plt.savefig('tmp_{:04d}.png'.format(counter)) 65 | counter += 1 66 | #time.sleep(0.2) 67 | -------------------------------------------------------------------------------- /py36-src/rod_odespy.py: -------------------------------------------------------------------------------- 1 | """Temperature evolution in a rod, computed by explicit odespy solvers.""" 2 | 3 | from numpy import linspace, zeros, linspace, array 4 | import matplotlib.pyplot as plt 5 | import time 6 | 7 | def rhs(u, t): 8 | N = len(u) - 1 9 | rhs = zeros(N+1) 10 | rhs[0] = dsdt(t) 11 | for i in range(1, N): 12 | rhs[i] = (beta/dx**2)*(u[i+1] - 2*u[i] + u[i-1]) + \ 13 | f(x[i], t) 14 | rhs[N] = (beta/dx**2)*(2*u[i-1] + 2*dx*dudx(t) - 15 | 2*u[i]) + f(x[N], t) 16 | return rhs 17 | 18 | def dudx(t): 19 | return 0 20 | 21 | def s(t): 22 | return 423 23 | 24 | def dsdt(t): 25 | return 0 26 | 27 | def f(x, t): 28 | return 0 29 | 30 | 31 | L = 1 32 | beta = 1 33 | N = 40 34 | x = linspace(0, L, N+1) 35 | dx = x[1] - x[0] 36 | u = zeros(N+1) 37 | 38 | U_0 = zeros(N+1) 39 | U_0[0] = s(0) 40 | U_0[1:] = 283 41 | dt = dx**2/(2*beta) 42 | print 'stability limit:', dt 43 | dt *= 100 44 | 45 | import odespy 46 | solver = odespy.RKFehlberg(rhs, rtol=1E-6, atol=1E-8) 47 | solver.set_initial_condition(U_0) 48 | T = 1.2 49 | N_t = int(round(T/float(dt))) 50 | time_points = linspace(0, T, N_t+1) 51 | u, t = solver.solve(time_points) 52 | 53 | # Check how many time steps required by adaptive vs 54 | # fixed-step methods 55 | if hasattr(solver, 't_all'): 56 | print '# time steps:', len(solver.t_all) 57 | plt.figure() 58 | plt.plot(array(solver.t_all[1:]) - array(solver.t_all[:-1])) 59 | plt.title('Evolution of the time step in %s' % solver.__class__.__name__) 60 | plt.savefig('tmp.png'); plt.savefig('tmp.pdf') 61 | plt.show() 62 | else: 63 | print '# time steps:', len(t) 64 | 65 | # Make movie 66 | import os 67 | os.system('rm tmp_*.png') 68 | plt.figure() 69 | plt.ion() 70 | y = u[0,:] 71 | lines = plt.plot(x, y) 72 | plt.axis([x[0], x[-1], 273, 1.2*s(0)]) 73 | plt.xlabel('x') 74 | plt.ylabel('u(x,t)') 75 | counter = 0 76 | for i in range(0, u.shape[0]): 77 | print t[i] 78 | lines[0].set_ydata(u[i,:]) 79 | plt.legend(['t=%.3f' % t[i]]) 80 | plt.draw() 81 | if i % 5 == 0: # plot every 5 steps 82 | plt.savefig('tmp_%04d.png' % counter) 83 | counter += 1 84 | #time.sleep(0.2) 85 | -------------------------------------------------------------------------------- /py36-src/rod_units.py: -------------------------------------------------------------------------------- 1 | from PhysicalQuantities import PhysicalQuantity as PQ 2 | rho = PQ('2.7E+3 kg/m**3') 3 | kappa = PQ('200 W/(m*K)') 4 | c = PQ('900 J/(K*kg)') 5 | beta = kappa/(rho*c) 6 | beta = PQ('%g m**2/s' % beta.getValue()) 7 | print beta 8 | -------------------------------------------------------------------------------- /py36-src/search_solutions_1eqn.py: -------------------------------------------------------------------------------- 1 | from numpy import linspace, sin, cos, exp, sqrt 2 | import matplotlib.pyplot as plt 3 | 4 | def f(x): 5 | return exp(sqrt(x))*sin(2*x) + cos(x)**5 + 8 6 | 7 | a = 0; b = 7; n = 200000 8 | dx = float(b-a)/n 9 | eps = 0.001 10 | 11 | for i in range(0, n+1, 1): 12 | x = a + i*dx 13 | f_value = f(x) 14 | if abs(f_value) < eps: 15 | print "x: %f , f_value: %f " % (x, f_value) 16 | 17 | x_plot = linspace(a, b, n+1) 18 | plt.plot(x_plot, f(x_plot), 'b-') 19 | plt.xlabel('x') 20 | plt.ylabel('f(x)') 21 | plt.grid('on') 22 | plt.show() 23 | plt.savefig('search_solutions_1eqn.pdf') 24 | -------------------------------------------------------------------------------- /py36-src/secant_method.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def secant(f, x0, x1, eps): 4 | f_x0 = f(x0) 5 | f_x1 = f(x1) 6 | iteration_counter = 0 7 | while abs(f_x1) > eps and iteration_counter < 100: 8 | try: 9 | denominator = (f_x1 - f_x0)/(x1 - x0) 10 | x = x1 - f_x1/denominator 11 | except ZeroDivisionError: 12 | print('Error! - denominator zero for x = ', x) 13 | sys.exit(1) # Abort with error 14 | x0 = x1 15 | x1 = x 16 | f_x0 = f_x1 17 | f_x1 = f(x1) 18 | iteration_counter = iteration_counter + 1 19 | # Here, either a solution is found, or too many iterations 20 | if abs(f_x1) > eps: 21 | iteration_counter = -1 22 | return x, iteration_counter 23 | 24 | if __name__ == '__main__': 25 | def f(x): 26 | return x**2 - 9 27 | 28 | x0 = 1000; x1 = x0 - 1 29 | 30 | solution, no_iterations = secant(f, x0, x1, eps=1.0e-6) 31 | 32 | if no_iterations > 0: # Solution found 33 | print('Number of function calls: {:d}'.format(2+no_iterations)) 34 | print('A solution is: {:f}'.format(solution)) 35 | else: 36 | print('Solution not found!') 37 | -------------------------------------------------------------------------------- /py36-src/swim_advisor.py: -------------------------------------------------------------------------------- 1 | T = float(input('What is the water temperature? ')) 2 | 3 | if T > 24: 4 | # testing condition 1 5 | print('Great, jump in!') 6 | elif 20 <= T <= 24: 7 | # testing condition 2 8 | print('Not bad. Put your toe in first!') 9 | else: 10 | print('Do not swim. Too cold!') 11 | # First line after if-elif-else construction -------------------------------------------------------------------------------- /py36-src/system_nonlin_eqns_Newton.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from numpy import matrix, sqrt 3 | 4 | def f(x, y): 5 | return matrix([[y - x**2, y - 2 + x**4]]) 6 | 7 | def J(x): 8 | return matrix([[-2*x, 1], [4*x**3, 1]]) 9 | 10 | x = matrix([[2.0, 2.0]]).T # Starting values 11 | f_eval = f(float(x[[0],[0]]), float(x[[1],[0]])) 12 | error_limit = 0.001 13 | no_iterations = 0 14 | it_limit = 100 15 | while sqrt(f_eval[[0],[0]]**2 + f_eval[[0],[1]]**2) > error_limit and \ 16 | no_iterations < it_limit: 17 | try: 18 | x = x - J(float(x[[0],[0]])).I*f(float(x[[0],[0]]),\ 19 | float(x[[1],[0]])).T 20 | print x, '\n' 21 | f_eval = f(float(x[[0],[0]]), float(x[[1],[0]])) 22 | no_iterations += 1 23 | except: 24 | print "Error! - Jacobian not invertible for x = ", x 25 | sys.exit(1) # Abort with error 26 | -------------------------------------------------------------------------------- /py36-src/test_diffusion_pde_exact_linear.py: -------------------------------------------------------------------------------- 1 | """Verify the implementation of the diffusion equation.""" 2 | 3 | from ode_system_FE import ode_FE 4 | import numpy as np 5 | 6 | def rhs(u, t): 7 | N = len(u) - 1 8 | rhs = np.zeros(N+1) 9 | rhs[0] = dsdt(t) 10 | for i in range(1, N): 11 | rhs[i] = (beta/dx**2)*(u[i+1] - 2*u[i] + u[i-1]) + \ 12 | g(x[i], t) 13 | rhs[N] = (beta/dx**2)*(2*u[N-1] + 2*dx*dudx(t) - 14 | 2*u[N]) + g(x[N], t) 15 | return rhs 16 | 17 | def u_exact(x, t): 18 | return (3*t + 2)*(x - L) 19 | 20 | def dudx(t): 21 | return (3*t + 2) 22 | 23 | def s(t): 24 | return u_exact(0, t) 25 | 26 | def dsdt(t): 27 | return 3*(-L) 28 | 29 | def g(x, t): 30 | return 3*(x-L) 31 | 32 | 33 | def verify_sympy_ForwardEuler(): 34 | import sympy as sp 35 | beta, x, t, dx, dt, L = sp.symbols('beta x t dx dt L') 36 | u = lambda x, t: (3*t + 2)*(x - L)**2 37 | f = lambda x, t, beta, L: 3*(x-L)**2 - (3*t + 2)*2*beta 38 | s = lambda t: (3*t + 2)*L**2 39 | N = 4 40 | rhs = [None]*(N+1) 41 | rhs[0] = sp.diff(s(t), t) 42 | for i in range(1, N): 43 | rhs[i] = (beta/dx**2)*(u(x+dx,t) - 2*u(x,t) + u(x-dx,t)) + \ 44 | f(x, t, beta, L) 45 | rhs[N] = (beta/dx**2)*(u(x-dx,t) + 2*dx*(3*t+2) - 46 | 2*u(x,t) + u(x-dx,t)) + f(x, t, beta, L) 47 | for i in range(len(rhs)): 48 | rhs[i] = sp.simplify(sp.expand(rhs[i])).subs(x, i*dx) 49 | print(rhs[i]) 50 | lhs = (u(x, t+dt) - u(x,t))/dt # Forward Euler difference 51 | lhs = sp.simplify(sp.expand(lhs.subs(x, i*dx))) 52 | print(lhs) 53 | print(sp.simplify(lhs - rhs[i])) 54 | print('---') 55 | 56 | def test_diffusion_exact_linear(): 57 | global beta, dx, L, x # needed in rhs 58 | L = 1.5 59 | beta = 0.5 60 | N = 4 61 | x = np.linspace(0, L, N+1) 62 | dx = x[1] - x[0] 63 | u = np.zeros(N+1) 64 | 65 | U_0 = np.zeros(N+1) 66 | U_0[0] = s(0) 67 | U_0[1:] = u_exact(x[1:], 0) 68 | dt = 0.1 69 | print(dt) 70 | 71 | u, t = ode_FE(rhs, U_0, dt, T=1.2) 72 | 73 | tol = 1E-12 74 | for i in range(0, u.shape[0]): 75 | diff = np.abs(u_exact(x, t[i]) - u[i,:]).max() 76 | assert diff < tol, 'diff={:.16g}'.format(diff) 77 | print('diff={:g} at t={:g}'.format(diff, t[i])) 78 | 79 | if __name__ == '__main__': 80 | test_diffusion_exact_linear() 81 | verify_sympy_ForwardEuler() 82 | -------------------------------------------------------------------------------- /py36-src/test_ode_FE_exact_linear.py: -------------------------------------------------------------------------------- 1 | from ode_FE import ode_FE 2 | 3 | def test_ode_FE(): 4 | """Test that a linear u(t)=a*t+b is exactly reproduced.""" 5 | 6 | def exact_solution(t): 7 | return a*t + b 8 | 9 | def f(u, t): # ODE 10 | return a + (u - exact_solution(t))**m 11 | 12 | a = 4 13 | b = -1 14 | m = 6 15 | 16 | dt = 0.5 17 | T = 20.0 18 | 19 | u, t = ode_FE(f, exact_solution(0), dt, T) 20 | diff = abs(exact_solution(t) - u).max() 21 | tol = 1E-15 # Tolerance for float comparison 22 | success = diff < tol 23 | assert success 24 | 25 | test_ode_FE() 26 | -------------------------------------------------------------------------------- /py36-src/test_trapezoidal.py: -------------------------------------------------------------------------------- 1 | from trapezoidal import trapezoidal 2 | 3 | def test_trapezoidal_one_exact_result(): 4 | """Compare one hand-computed result.""" 5 | from math import exp 6 | v = lambda t: 3*(t**2)*exp(t**3) 7 | n = 2 8 | computed = trapezoidal(v, 0, 1, n) 9 | expected = 2.463642041244344 10 | error = abs(expected - computed) 11 | tol = 1E-14 12 | success = error < tol 13 | msg = 'error={:g} > tol={:g}'.format(error, tol) 14 | assert success, msg 15 | 16 | def test_trapezoidal_linear(): 17 | """Check that linear functions are integrated exactly.""" 18 | f = lambda x: 6*x - 4 19 | F = lambda x: 3*x**2 - 4*x # Anti-derivative 20 | a = 1.2; b = 4.4 21 | expected = F(b) - F(a) 22 | tol = 1E-14 23 | for n in 2, 20, 21: 24 | computed = trapezoidal(f, a, b, n) 25 | error = abs(expected - computed) 26 | success = error < tol 27 | msg = 'n={:d}, err={:g}'.format(n, error) 28 | assert success, msg 29 | 30 | def convergence_rates(f, F, a, b, num_experiments=14): 31 | from math import log 32 | from numpy import zeros 33 | expected = F(b) - F(a) 34 | n = zeros(num_experiments, dtype=int) 35 | E = zeros(num_experiments) 36 | r = zeros(num_experiments-1) 37 | for i in range(num_experiments): 38 | n[i] = 2**(i+1) 39 | computed = trapezoidal(f, a, b, n[i]) 40 | E[i] = abs(expected - computed) 41 | if i > 0: 42 | r_im1 = -log(E[i]/E[i-1])/log(n[i]/n[i-1]) 43 | # Truncate to two decimals: 44 | r[i-1] = float('{:.2f}'.format(r_im1)) 45 | return r 46 | 47 | def test_trapezoidal_conv_rate(): 48 | """Check empirical convergence rates against the expected value 2.""" 49 | from math import exp 50 | v = lambda t: 3*(t**2)*exp(t**3) 51 | V = lambda t: exp(t**3) 52 | a = 1.1; b = 1.9 53 | r = convergence_rates(v, V, a, b, 14) 54 | print(r) 55 | tol = 0.01 56 | msg = str(r[-4:]) # show last 4 estimated rates 57 | assert (abs(r[-1]) - 2) < tol, msg 58 | 59 | -------------------------------------------------------------------------------- /py36-src/throw_2_dice.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | a = 1; b = 6 4 | r1 = random.randint(a, b) # first die 5 | r2 = random.randint(a, b) # second die 6 | 7 | print('The dice gave: {:d} and {:d}'.format(r1, r2)) 8 | -------------------------------------------------------------------------------- /py36-src/times_tables_1.py: -------------------------------------------------------------------------------- 1 | def ask_user(a, b): # preliminary 2 | """get answer from user: a*b = ?""" 3 | print('{:d}*{:d} = '.format(a, b)) 4 | return a*b 5 | 6 | def points(a, b, answer_given): # preliminary 7 | """Check answer. Correct: 1 point, else 0""" 8 | print('{:d}*{:d} = {:d}'.format(a, b, a*b)) 9 | return 1 10 | 11 | print('\n*** Welcome to the times tables test! ***\ 12 | \n (To stop: ctrl-c)') 13 | 14 | # Ask user for a*b, ... a, b are in [1, N] 15 | N = 2 16 | score = 0 17 | for i in range(1, N+1, 1): 18 | for j in range(1, N+1, 1): 19 | user_answer = ask_user(i, j) 20 | score = score + points(i, j, user_answer) 21 | print('Your score is now: {:d}'.format(score)) 22 | 23 | print('\nFinished! \nYour final score: {:d} (max: {:d})'\ 24 | .format(score, N*N)) 25 | 26 | -------------------------------------------------------------------------------- /py36-src/times_tables_2.py: -------------------------------------------------------------------------------- 1 | def ask_user(a, b): 2 | """get answer from user: a*b = ?""" 3 | question = '{:d} * {:d} = '.format(a, b) 4 | answer = int(input(question)) 5 | return answer 6 | 7 | def points(a, b, answer_given): 8 | """Check answer. Correct: 1 point, else 0""" 9 | true_answer = a*b 10 | if answer_given == true_answer: 11 | print('Correct!') 12 | return 1 13 | else: 14 | print('Sorry! Correct answer was: {:d}'.format(true_answer)) 15 | return 0 16 | 17 | print('\n*** Welcome to the times tables test! ***\ 18 | \n (To stop: ctrl-c)') 19 | 20 | # Ask user for a*b, ... a, b are in [1, N] 21 | N = 2 22 | score = 0 23 | for i in range(1, N+1, 1): 24 | for j in range(1, N+1, 1): 25 | user_answer = ask_user(i, j) 26 | score = score + points(i, j, user_answer) 27 | print('Your score is now: {:d}'.format(score)) 28 | 29 | print('\nFinished! \nYour final score: {:d} (max: {:d})'\ 30 | .format(score, N*N)) -------------------------------------------------------------------------------- /py36-src/times_tables_3.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def ask_user(a, b): 4 | """get answer from user: a*b = ?""" 5 | question = '{:d} * {:d} = '.format(a, b) 6 | answer = int(input(question)) 7 | return answer 8 | 9 | def points(a, b, answer_given): 10 | """Check answer. Correct: 1 point, else 0""" 11 | true_answer = a*b 12 | if answer_given == true_answer: 13 | print('Correct!') 14 | return 1 15 | else: 16 | print('Sorry! Correct answer was: {:d}'.format(true_answer)) 17 | return 0 18 | 19 | print('\n*** Welcome to the times tables test! ***\ 20 | \n (To stop: ctrl-c)') 21 | 22 | N = 10 23 | NN = N*N 24 | score = 0 25 | index = list(range(0, NN, 1)) 26 | np.random.shuffle(index) # randomize order of integers in index 27 | for i in range(0, NN, 1): 28 | a = (index[i]//N) + 1 29 | b = index[i]%N + 1 30 | user_answer = ask_user(a, b) 31 | 32 | score = score + points(a, b, user_answer) 33 | print('Your score is now: {:d}'.format(score)) 34 | 35 | print('\nFinished! \nYour final score: {:d} (max: {:d})'\ 36 | .format(score, N*N)) 37 | -------------------------------------------------------------------------------- /py36-src/times_tables_4.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def ask_user(a, b): 4 | """Get answer from user: a*b = ?""" 5 | question = '{:d} * {:d} = '.format(a, b) 6 | answer = int(input(question)) 7 | return answer 8 | 9 | def points(a, b, answer_given): 10 | """Check answer. Correct answer gives 1 point, else zero""" 11 | true_answer = a*b 12 | if answer_given == true_answer: 13 | print('Correct!') 14 | return 1 15 | else: 16 | print('Sorry! Correct answer was: {:d}'.format(true_answer)) 17 | return 0 18 | 19 | print('\n*** Welcome to the times tables test! ***\ 20 | \n (To stop: ctrl-c)') 21 | 22 | N = 10 23 | NN = N*N 24 | score = 0 25 | index = list(range(0, NN, 1)) 26 | np.random.shuffle(index) # randomize order of integers in index 27 | for i in range(0, NN, 1): 28 | a = index[i]//N + 1 29 | b = index[i]%N + 1 30 | try: 31 | user_answer = ask_user(a, b) 32 | except KeyboardInterrupt: 33 | print('\nOk, you want to stop!') 34 | break 35 | except ValueError: 36 | print('You must give a valid number!') 37 | continue # jump to next loop iteration 38 | 39 | score = score + points(a, b, user_answer) 40 | print('Your score is now: {:d}'.format(score)) 41 | 42 | print('\nFinished! \nYour final score: {:d} (max: {:d})'\ 43 | .format(score, N*N)) 44 | 45 | -------------------------------------------------------------------------------- /py36-src/timing_function_call.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | import numpy as np 3 | 4 | def add(a, b): 5 | return a + b 6 | 7 | x = np.zeros(1000) 8 | y = np.zeros(1000) 9 | 10 | # ...use the function add 11 | t = timeit.Timer('for i in range(len(x)): x[i] = add(i, i+1)', \ 12 | setup='from __main__ import add, x') 13 | x_time = t.timeit(10000) # Time 10000 runs of the whole loop 14 | print('Time, function call: {:g} seconds'.format(x_time)) 15 | 16 | # ...no use of function add 17 | t = timeit.Timer('for i in range(len(y)): y[i] = i + (i+1)', \ 18 | setup='from __main__ import y') 19 | y_time = t.timeit(10000) # Time 10000 runs of the whole loop 20 | print('Time: {:g} seconds'.format(y_time)) 21 | -------------------------------------------------------------------------------- /py36-src/timing_midpoint_vec.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | from integration_methods_vec import midpoint as midpoint_vec 3 | from midpoint import midpoint 4 | from numpy import exp 5 | 6 | v = lambda t: 3*t**2*exp(t**3) 7 | 8 | t = timeit.Timer('midpoint(v, 0, 1, 1000000)', \ 9 | setup='from __main__ import midpoint, v') 10 | time_midpoint = t.timeit(10) 11 | print('Time, midpoint: {:g} seconds'.format(time_midpoint)) 12 | 13 | # Vectorized version 14 | t = timeit.Timer('midpoint_vec(v, 0, 1, 1000000)', \ 15 | setup='from __main__ import midpoint_vec, v') 16 | time_midpoint_vec = t.timeit(10) 17 | print('Time, midpoint vec: {:g} seconds'.format(time_midpoint_vec)) 18 | 19 | print('Efficiency factor: {:g}'.format(time_midpoint/time_midpoint_vec)) 20 | -------------------------------------------------------------------------------- /py36-src/trapezoidal.py: -------------------------------------------------------------------------------- 1 | def trapezoidal(f, a, b, n): 2 | h = (b-a)/n 3 | f_sum = 0 4 | for i in range(1, n, 1): 5 | x = a + i*h 6 | f_sum = f_sum + f(x) 7 | return h*(0.5*f(a) + f_sum + 0.5*f(b)) 8 | 9 | def application(): 10 | from math import exp 11 | v = lambda t: 3*(t**2)*exp(t**3) 12 | n = int(input('n: ')) 13 | numerical = trapezoidal(v, 0, 1, n) 14 | 15 | # Compare with exact result 16 | V = lambda t: exp(t**3) 17 | exact = V(1) - V(0) 18 | error = abs(exact - numerical) 19 | print('n={:d}: {:.16f}, error: {:g}'.format(n, numerical, error)) 20 | 21 | if __name__ == '__main__': 22 | application() -------------------------------------------------------------------------------- /py36-src/trapezoidal_flat.py: -------------------------------------------------------------------------------- 1 | from math import exp 2 | 3 | v = lambda t: 3*(t**2)*exp(t**3) # Define integrand 4 | a = 0.0; b = 1.0 5 | n = int(input('n: ')) 6 | dt = (b - a)/n 7 | 8 | # Integral by the trapezoidal method 9 | v_sum = 0 10 | for i in range(1, n, 1): 11 | t = a + i*dt 12 | v_sum = v_sum + v(t) 13 | numerical = dt*(0.5*v(a) + v_sum + 0.5*v(b)) 14 | 15 | V = lambda t: exp(t**3) 16 | exact_value = V(b) - V(a) 17 | error = abs(exact_value - numerical) 18 | rel_error = (error/exact_value)*100 19 | print('n={:d}: {:.16f}, error: {:g}'.format(n, numerical, error)) 20 | -------------------------------------------------------------------------------- /py36-src/trapezoidal_flat1.py: -------------------------------------------------------------------------------- 1 | from math import exp 2 | 3 | a = 0.0; b = 1.0 4 | n = int(input('n: ')) 5 | dt = (b - a)/n 6 | 7 | # Integral by the trapezoidal method 8 | v_sum = 0 9 | for i in range(1, n, 1): 10 | t = a + i*dt 11 | v_sum = v_sum + 3*(t**2)*exp(t**3) 12 | 13 | numerical = dt*(0.5*3*(a**2)*exp(a**3) + 14 | v_sum + 15 | 0.5*3*(b**2)*exp(b**3)) 16 | 17 | exact_value = exp(1**3) - exp(0**3) 18 | error = abs(exact_value - numerical) 19 | rel_error = (error/exact_value)*100 20 | print('n={:d}: {:.16f}, error: {:g}'.format(n, numerical, error)) 21 | -------------------------------------------------------------------------------- /py36-src/two_plots_one_fig.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | plt.subplot(2, 1, 1) # 2 rows, 1 column, plot number 1 5 | v0 = 5 6 | g = 9.81 7 | t = np.linspace(0, 1, 11) 8 | y = v0*t - 0.5*g*t**2 9 | plt.plot(t, y, '*') 10 | plt.xlabel('t (s)') 11 | plt.ylabel('y (m)') 12 | plt.title('Ball moving vertically') 13 | 14 | plt.subplot(2, 1, 2) # 2 rows, 1 column, plot number 2 15 | t = np.linspace(-2, 2, 100) 16 | f_values = t**2 17 | g_values = np.exp(t) 18 | plt.plot(t, f_values, 'r', t, g_values, 'b--') 19 | plt.xlabel('t') 20 | plt.ylabel('f and g') 21 | plt.legend(['t**2', 'e**t']) 22 | plt.title('Plotting of two functions (t**2 and e**t)') 23 | plt.grid('on') 24 | plt.axis([-3, 3, -1, 10]) 25 | 26 | plt.tight_layout() # make subplots fit figure area 27 | plt.show() 28 | -------------------------------------------------------------------------------- /py36-src/vertical_motion.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for computing vertical motion 3 | characteristics for a projectile. 4 | """ 5 | def y(v0, t): 6 | """ 7 | Compute vertical position at time t, given the initial vertical 8 | velocity v0. Assume negligible air resistance. 9 | """ 10 | g = 9.81 11 | return v0*t - 0.5*g*t**2 12 | 13 | def time_of_flight(v0): 14 | """ 15 | Compute time in the air, given the initial vertical 16 | velocity v0. Assume negligible air resistance. 17 | """ 18 | g = 9.81 19 | return 2*v0/g 20 | 21 | def max_height(v0): 22 | """ 23 | Compute maximum height reached, given the initial vertical 24 | velocity v0. Assume negligible air resistance. 25 | """ 26 | g = 9.81 27 | return v0**2/(2*g) 28 | 29 | def application(): 30 | import numpy as np 31 | import matplotlib.pyplot as plt 32 | import sys 33 | 34 | print("""This program computes vertical motion characteristics for a 35 | projectile. Given the intial vertical velocity, it computes height 36 | (as it develops with time), maximum height reached, as well as time 37 | of flight.""") 38 | 39 | try: 40 | v_initial = float(input('Give the initial velocity: ')) 41 | except: 42 | print('You must give a valid number!') 43 | sys.exit(1) 44 | 45 | H = max_height(v_initial) 46 | T = time_of_flight(v_initial) 47 | print('Maximum height: {:g} m, \nTime of flight: {:g} s'.format(H, T)) 48 | 49 | # compute and plot position as function of time 50 | dt = 0.001 51 | # just pick a "small" time step 52 | N = int(T/dt) 53 | # number of time steps 54 | t = np.linspace(0, N*dt, N+1) 55 | position = y(v_initial, t) 56 | # compute all positions (over T) 57 | plt.plot(t, position, 'b--') 58 | plt.xlabel('Time (s)') 59 | plt.ylabel('Vertical position (m)') 60 | plt.show() 61 | return 62 | 63 | if __name__ == '__main__': 64 | application() -------------------------------------------------------------------------------- /py36-src/viz_midpoint.py: -------------------------------------------------------------------------------- 1 | """Visualize the Midpoint integration method.""" 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | def viz_midpoint(f, x_points): 7 | 8 | def midpoint(x_points, f, samples_per_interval=31): 9 | # Compute element by element in case f does not work with array x 10 | x = [] 11 | y = [] 12 | y_exact = [] 13 | for i in range(len(x_points)-1): 14 | mid = 0.5*(x_points[i] + x_points[i+1]) 15 | yi = f(mid) 16 | dx = (x_points[i+1] - x_points[i])/float(samples_per_interval-1) 17 | for j in range(samples_per_interval): 18 | xi = x_points[i] + j*dx 19 | x.append(xi) 20 | y.append(yi) 21 | y_exact.append(f(xi)) 22 | return np.array(x), np.array(y), np.array(y_exact) 23 | 24 | def midpoint_geometry(x_points, f): 25 | x = [] 26 | y = [] 27 | for i in range(len(x_points)-1): 28 | x.append(x_points[i]) 29 | y.append(0) 30 | mid = 0.5*(x_points[i] + x_points[i+1]) 31 | fmid = f(mid) 32 | x.append(x_points[i]) 33 | y.append(fmid) 34 | x.append(x_points[i+1]) 35 | y.append(fmid) 36 | x.append(x_points[i+1]) 37 | y.append(0) 38 | return np.array(x), np.array(y) 39 | 40 | x, y, y_e = midpoint(x_points, f, 31) 41 | bx, by = midpoint_geometry(x_points, f) 42 | plt.plot(x, y_e, 'k-', linewidth=3) 43 | #plt.fill_between(x, y, y_e) 44 | #plt.plot(bx, by, 'r-') 45 | plt.fill(bx, by, 'r--') 46 | plt.savefig('tmp_midpoint.pdf'); plt.savefig('tmp_midpoint.png') 47 | plt.show() 48 | 49 | if __name__ == '__main__': 50 | def v(t): 51 | return 3*t**2*np.exp(t**3) 52 | 53 | x_points = np.array([0, 0.2, 0.6, 0.8, 1.0]) 54 | viz_midpoint(v, x_points) 55 | -------------------------------------------------------------------------------- /py36-src/viz_rectangle.py: -------------------------------------------------------------------------------- 1 | """Visualize the Midpoint integration method.""" 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | def viz_rectangle(f, x_points, height='mid'): 7 | 8 | def rectangle(x_points, f, samples_per_interval=31): 9 | # Compute element by element in case f does not work with array x 10 | x = [] 11 | y = [] 12 | y_exact = [] 13 | for i in range(len(x_points)-1): 14 | if height == 'mid': 15 | mid = 0.5*(x_points[i] + x_points[i+1]) 16 | elif height == 'left': 17 | mid = x_points[i] 18 | elif height == 'right': 19 | mid = x_points[i+1] 20 | 21 | yi = f(mid) 22 | dx = (x_points[i+1] - x_points[i])/float(samples_per_interval-1) 23 | for j in range(samples_per_interval): 24 | xi = x_points[i] + j*dx 25 | x.append(xi) 26 | y.append(yi) 27 | y_exact.append(f(xi)) 28 | return np.array(x), np.array(y), np.array(y_exact) 29 | 30 | def rectangle_geometry(x_points, f): 31 | x = [] 32 | y = [] 33 | for i in range(len(x_points)-1): 34 | x.append(x_points[i]) 35 | y.append(0) 36 | if height == 'mid': 37 | mid = 0.5*(x_points[i] + x_points[i+1]) 38 | elif height == 'left': 39 | mid = x_points[i] 40 | elif height == 'right': 41 | mid = x_points[i+1] 42 | fmid = f(mid) 43 | x.append(x_points[i]) 44 | y.append(fmid) 45 | x.append(x_points[i+1]) 46 | y.append(fmid) 47 | x.append(x_points[i+1]) 48 | y.append(0) 49 | return np.array(x), np.array(y) 50 | 51 | x, y, y_e = rectangle(x_points, f, 31) 52 | bx, by = rectangle_geometry(x_points, f) 53 | plt.plot(x, y_e, 'k-', linewidth=3) 54 | #plt.fill_between(x, y, y_e) 55 | #plt.plot(bx, by, 'r-') 56 | plt.fill(bx, by, 'r--') 57 | plt.savefig('tmp_rectangle.pdf'); plt.savefig('tmp_rectangle.png') 58 | plt.show() 59 | 60 | if __name__ == '__main__': 61 | def v(t): 62 | return 3*t**2*np.exp(t**3) 63 | 64 | x_points = np.array([0, 0.2, 0.6, 0.8, 1.0]) 65 | import sys 66 | viz_rectangle(v, x_points, sys.argv[1]) 67 | -------------------------------------------------------------------------------- /py36-src/viz_trapezoidal.py: -------------------------------------------------------------------------------- 1 | """Visualize the Trapezoidal integration method.""" 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | def viz_trapezoidal(f, x_points): 7 | 8 | def trapezoidal(x_points, f, samples_per_interval=31): 9 | # Compute element by element in case f does not work with x 10 | x = [] 11 | y = [] 12 | y_exact = [] 13 | for i in range(len(x_points)-1): 14 | dx = (x_points[i+1] - x_points[i])/float(samples_per_interval-1) 15 | 16 | def trapez(x): 17 | return f(x_points[i]) + \ 18 | (f(x_points[i+1])-f(x_points[i]))/\ 19 | (x_points[i+1]-x_points[i])*(x - x_points[i]) 20 | 21 | for j in range(samples_per_interval): 22 | xi = x_points[i] + j*dx 23 | x.append(xi) 24 | y.append(trapez(xi)) 25 | y_exact.append(f(xi)) 26 | return x, np.array(y), np.array(y_exact) 27 | 28 | def trapez_geometry(x_points, f): 29 | x = [] 30 | y = [] 31 | for i in range(len(x_points)-1): 32 | x.append(x_points[i]) 33 | y.append(0) 34 | x.append(x_points[i]) 35 | y.append(f(x_points[i])) 36 | x.append(x_points[i+1]) 37 | y.append(f(x_points[i+1])) 38 | x.append(x_points[i+1]) 39 | y.append(0) 40 | return np.array(x), np.array(y) 41 | 42 | x, y, y_e = trapezoidal(x_points, f, 31) 43 | bx, by = trapez_geometry(x_points, f) 44 | plt.plot(x, y_e, 'k-', linewidth=3) 45 | #plt.fill_between(x, y, y_e) 46 | #plt.plot(bx, by, 'r--') 47 | plt.fill(bx, by, 'r--') 48 | plt.savefig('tmp_trapezoidal.pdf'); plt.savefig('tmp_trapezoidal.png') 49 | # Show integral of f 50 | plt.figure() 51 | x = np.linspace(x_points[0], x_points[-1], 501) 52 | y = f(x) 53 | plt.fill_between(x, y, 0, facecolor='white', hatch='/') 54 | plt.savefig('tmp_intf.pdf'); plt.savefig('tmp_intf.png') 55 | plt.show() 56 | 57 | if __name__ == '__main__': 58 | def v(t): 59 | return 3*t**2*np.exp(t**3) 60 | 61 | x_points = np.array([0, 0.2, 0.6, 0.8, 1.0]) 62 | viz_trapezoidal(v, x_points) 63 | --------------------------------------------------------------------------------