{"_id":"@b3gm/ode-to-joy","_rev":"1-9a47d07fa816a6a6cb8c0cbee3af7baa","name":"@b3gm/ode-to-joy","dist-tags":{"latest":"0.0.3"},"versions":{"0.0.1":{"name":"@b3gm/ode-to-joy","version":"0.0.1","description":"Solvers for ordinary differential equations.","main":"dist/index.js","scripts":{"clean":"rm -rf dist test-dist && rm -f ode-to-joy.tgz","test":"npx jest","test:coverage":"npx jest --collect-coverage","build:production":"npx tsc -p tsconfig.prod.json","start:dev":"npx webpack serve -c webpack.testconfig.ts","prepare":"npm run clean && npm run build:production"},"repository":{"type":"git","url":"git+https://github.com/b3gm/ode-to-joy.git"},"keywords":["ordinary_differential_equations","ode","initial_value_problem","runge_kutta","heun_method","midpoint_method","explicit_euler_method","integration"],"author":{"name":"b3gm"},"license":"MIT","bugs":{"url":"https://github.com/b3gm/ode-to-joy/issues"},"homepage":"https://github.com/b3gm/ode-to-joy#readme","devDependencies":{"@b3gm/algebr4":"^1.0.1","@types/html-webpack-plugin":"^3.2.6","@types/jest":"^29.4.0","@types/three":"^0.149.0","@types/webpack":"^5.28.0","html-loader":"^4.2.0","html-webpack-plugin":"^5.5.0","jest":"^29.4.2","three":"^0.149.0","ts-jest":"^29.0.5","ts-loader":"^9.4.2","ts-node":"^10.9.1","typescript":"^4.9.5","webpack-cli":"^5.0.1","webpack-dev-server":"^4.11.1"},"dependencies":{},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"types":"./dist/index.d.ts","gitHead":"cb2ebde65a028116c8ca2f452bf0ba3bab7eae9c","_id":"@b3gm/ode-to-joy@0.0.1","_nodeVersion":"16.20.0","_npmVersion":"8.19.4","dist":{"integrity":"sha512-Gu+OfBsLMyP3yUWA2ONUhEnU0GqDn52HQg6sKl6dMkEi/w0+AmAS+JI67KNhvUmkymHcSNibCTR73c88ChGvzQ==","shasum":"9fc3d0c83d5d149bdc8a54cf3cd3cdc7a368b121","tarball":"https://registry.npmjs.org/@b3gm/ode-to-joy/-/ode-to-joy-0.0.1.tgz","fileCount":25,"unpackedSize":33750,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBzqlrD41GbSwqgDdmSSiYYHo+1vWoEZSm1cvqTwvV2XAiAX97HYYlL2iidCCz/tMI8EVXlU1fEtp8PLonwMqK7Hig=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkOabmACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo1dQ//Y4hYid73KFKCypRP/WfqDj4nnwTU4YXvNpPObqlDv2CkX3mj\r\n+kfeBxcqSy6j6n/igfIw8V0IznNJOOOIpX7kx1CwYzKOmFN3hPqZ8m9LBprf\r\nPVCLsW+PBJlP3RCkuI65b0xjmREBIKju9dgrwNr8Uku5H2ftfou84P0I6sBn\r\nU0hCYzxfKVrungoy0dbPd2BFYgSI3nfw9lGtAKuaL4L4UYI2KvqofQyeJsGI\r\n3CjwiYKejcI4VuoQzTf6X2O2yXZU9TDYKw36Nz1zDdK+ZJHawtSWfmPIkjln\r\nI3wyvVkuLGQsdALaOe+vXZ5CHq8yTQHVkVTzmnzy5jKo1IR9B0qQ5L/v9HkD\r\nv5uKyLx+0VxcGVo5jCf6ehLdPKuzzgPnJty1c6qIDhPAo1H4Nrvqtlbs7xrG\r\n9ZyTVnzpdVZp4N2CGiY+9oIPJQ95W8wBhozo+CjA/tpyOjbKnvPLJG13cmYm\r\nEcb/eHkYfA/AIBcoKd7WVk1VhsYEBjcNbLSYJar2rpltjIds//w981tRSFvg\r\nWz7tDlKljBkI7tPf7hJmwnlMCmdKHjhViwYv6jl3JlxuEuOl6iUoiO+mSsCe\r\nLpg3d0pwrTuqLRGzvIUr0OrpG7su/njk+THLMD0vMvEePvJnSpRzSe/TxVFT\r\nm9BOlQUaDMKMQmZCWrU7JU4iU0wEwXyDD50=\r\n=M1zy\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"pguenther","email":"p.guenther86@gmail.com"},"directories":{},"maintainers":[{"name":"pguenther","email":"p.guenther86@gmail.com"},{"name":"tmpbigg","email":"b3gmde@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ode-to-joy_0.0.1_1681499877813_0.9410163869800308"},"_hasShrinkwrap":false},"0.0.3":{"name":"@b3gm/ode-to-joy","version":"0.0.3","description":"Solvers for ordinary differential equations.","main":"dist/index.js","scripts":{"clean":"rm -rf dist test-dist && rm -f ode-to-joy.tgz","lint":"npx eslint .","test":"npx jest","test:coverage":"npx jest --collect-coverage","build:production":"npx tsc -p tsconfig.prod.json","start:dev":"npx webpack serve -c webpack.testconfig.ts","prepare":"npm run clean && npm run build:production"},"repository":{"type":"git","url":"git+https://github.com/b3gm/ode-to-joy.git"},"keywords":["ordinary_differential_equations","ode","initial_value_problem","runge_kutta","heun_method","midpoint_method","explicit_euler_method","integration"],"author":{"name":"b3gm"},"license":"MIT","bugs":{"url":"https://github.com/b3gm/ode-to-joy/issues"},"homepage":"https://github.com/b3gm/ode-to-joy#readme","devDependencies":{"@b3gm/algebr4":"^1.0.2","@types/html-webpack-plugin":"^3.2.6","@types/jest":"^29.4.0","@types/three":"^0.149.0","@types/webpack":"^5.28.0","@typescript-eslint/eslint-plugin":"^5.59.1","@typescript-eslint/parser":"^5.59.1","eslint":"^8.39.0","html-loader":"^4.2.0","html-webpack-plugin":"^5.5.0","jest":"^29.4.2","three":"^0.149.0","ts-jest":"^29.0.5","ts-loader":"^9.4.2","ts-node":"^10.9.1","typescript":"^4.9.5","webpack-cli":"^5.0.1","webpack-dev-server":"^4.11.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"types":"./dist/index.d.ts","gitHead":"0ab297a086c287abd600d327e01cc3759076d8e7","_id":"@b3gm/ode-to-joy@0.0.3","_nodeVersion":"16.20.0","_npmVersion":"8.19.4","dist":{"integrity":"sha512-DaV5sqAEiTFxEu0HPBdY320Yyg0EWbeHlIqTxW9EUatrjAEbK584D9fNYPcKFHHhfoZwKL4iJhReh0s3F2V+gQ==","shasum":"d9aedf5d1897ca9f660bc643e4a2558ff0dd004e","tarball":"https://registry.npmjs.org/@b3gm/ode-to-joy/-/ode-to-joy-0.0.3.tgz","fileCount":25,"unpackedSize":34135,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE74Os9bNrAyLWUhQWg8nRAeXng7w1znuBBFCDyRDhLgAiEArcwFDgi841mYGEup+/yFvDXvd39quZY4YGrVZXKHsSo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkSCbcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrzww/+J7j80hunVudApOfTge8O/fdUGNynAfaZ32lgSkXK4fmhcTPc\r\nzsot1q1QqoN/wrsGBNPnp1Yy66xBBu9Q8UUPLMNeXTYCwIQKmaySU6K4xryb\r\nu69S08e+75nCkjrGca9RC3Ru3L6gC6Asfc0x45rVCIixsqkk3bIpAOz6UsVN\r\nseJfpb9zDFG++LV9sNOVh7LrK9zzHszFqWDDb3MQU9ycfWaXDHn/wjKFoeah\r\nHpZwN0xAIw02ETR96ecJJWw0LvsIKLhzvYw/3eBZ3PnilUcDt07z9jOSttmX\r\nryF2Bb1m/bvviVLTKeuqnkABeZhPd2jYOFTRCo1oEg5YFvRRSNo2/2x+7X0m\r\nsfQq3x1YLc6u7iXiCOyFPmY5xyj/ZDeRlALWTjZeiHjf4xmYO2PhcusCm+Z9\r\n7IQ/2GeqooTxN+MgWyPXFM+AXaEbT2YJtJIOh9nD7FKPrSnYrzB9aqe0Cb68\r\nXNKS8HgmrG7xsB6X3se3XmzhVd94fRJpov9zTHvfz1s0ah5ENI9ynZE7fATj\r\nyXaqDTD9p9il8feMNYn1bPF+KPNI83scJn+jf9L3k8OrfWqoWcpC/FMkCJnZ\r\nLBz8aZ21CPTba8DkVVk07Bh7tr/LA3rG+zkmXMXABKaiKYcWThz402iwtoaa\r\nZCfNXwxRMFs9cLLREDNfaCvaRo3y/F6qPrI=\r\n=Fz2R\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"pguenther","email":"p.guenther86@gmail.com"},"directories":{},"maintainers":[{"name":"pguenther","email":"p.guenther86@gmail.com"},{"name":"tmpbigg","email":"b3gmde@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ode-to-joy_0.0.3_1682450140609_0.8632655446329036"},"_hasShrinkwrap":false}},"time":{"created":"2023-04-14T19:17:57.749Z","0.0.1":"2023-04-14T19:17:57.999Z","modified":"2023-04-25T19:15:40.923Z","0.0.3":"2023-04-25T19:15:40.769Z"},"maintainers":[{"name":"pguenther","email":"p.guenther86@gmail.com"},{"name":"tmpbigg","email":"b3gmde@gmail.com"}],"description":"Solvers for ordinary differential equations.","homepage":"https://github.com/b3gm/ode-to-joy#readme","keywords":["ordinary_differential_equations","ode","initial_value_problem","runge_kutta","heun_method","midpoint_method","explicit_euler_method","integration"],"repository":{"type":"git","url":"git+https://github.com/b3gm/ode-to-joy.git"},"author":{"name":"b3gm"},"bugs":{"url":"https://github.com/b3gm/ode-to-joy/issues"},"license":"MIT","readme":"ode-to-joy\n==========\n\nTypescript implementation of solvers for ordinary differential equations\nand integrating initial value problems.\n\n\nProblem Description\n-------------------\n\nThis library solves initial value problems of the form\n\n```\ny'(t) = f(y(t))\nwith initial value: y(t_0) = y_0\n```\n\nfor unknown vector-valued functions `y(t): R -> R^N` where `f(y(t))` denotes its derivative at point `y(t)`. The real variable `t` is often regarded as the time for physical the systems.\n\nSince the time variable usually increases linearly not dependent on the state of the system, it is usually eliminated from the problem description and variables:\n\n```\ny' = f(y)\nwith initial value y_0\n```\n\nThis library solves the initial value problem using different explicit, single-step [Runge-Kutta methods](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods).\n\nOde-to-joy's architecture is separated into the following two layers:\n\n- A math layer that implements the actual solvers. Points `y` are modeled using javascript's built-in `Float64Array`s\n- An optional mapping layer that can be used to map float values from those arrays into your business objects and vice versa.\n\n\nMath Layer\n----------\n\nThe different solvers are exported as `explicitSolvers`. Implicit solvers might be added in the future.\n\nAll explicit solvers implement the following interface\n\n```typescript\nexport type ExplicitSolver = (\n  current: Float64Array,\n  stepSize: number,\n  fDash: (current: Float64Array) => Float64Array\n) => Float64Array;\n```\n\nwhere `current` is `y_0` from the problem description for a single execution, `stepSize` is the increment in time and `fDash` is used by the solver to sample the derivative of `y` at different points. For calculating a solution over longer periods of time, this function has to be called repeatedly by feeding the result of one step into the `current` parameter of the next invocation.\n\nLowering the step size parameter produces lower errors for integrating the equation but will also be more computationally expensive for covering the same period in time. The rate at which this error falls depends on the solver being used and can be expressed as\n\n```\n| y_h(t) - y(t) | = O(h^n), for h approaches 0\n```\n\nwhere the parameter `h` is the step size, `O` is the Landau symbol \"big O\", `y_h(t)` is the approximated solution of the initial value problem, which was found using step size `h` and `y(t)` is the real solution of the initial value problem (which typically cannot be computed analytically). The integer parameter `n` depends on the solver being used. Solvers with higher values of `n` produce smaller errors for a given step size but also need to sample the derivative `fDash` more often.\n\nAs a simple example the one-dimensional initial value problem\n\n```\ny'(t) = y(t)\ny_0 = 1.0\n```\n\ncan be integrated as follows using a step size of `0.01`:\n\n```typescript\nimport { explicitSolvers } from \"@b3gm/ode-to-joy\";\n\n\nlet current = new Float64Array(1);\ncurrent[0] = 1;\nfor (let i = 0; i != 100; ++i) {\n  current = explicitSolvers.rungeKutta4(\n    current,\n    0.01,\n    v => v // fDash: y' = y\n  );\n}\nconsole.log(\"Solution:\", current[0]); // 2.718281828234403\n```\n\nMapping Layer - Array Backed Types\n----------------------------------\n\nOde-to-joy provides an optional mapping layer to help out with mapping the above-mentioned `Float64Array` to and from your own or third-party business objects. This lets you express the derivative `fDash` in terms of the domain of your choice, hopefully making its implementation more readable and eliminating the need for your domain objects to keep track of their host array indices.\n\nFor this mapping layer to work, you need to provide a corresponding description of so-called \"array-backed\" types, which can be constructed and composed with each other by using the provided factory methods exported via `abTypes`:\n\n- `abTypes.float(): ABType<number>`: The most primitive array-backed type, maps a single float between your objects and `Float64Array`s.\n- `abTypes.object<T>(props: ABObjectDescription<T>): ABType<T>`: Mapps between arrays and mutable object types by directly writing values to your objects using the regular property accessor `[propertyName]`. The object description might only contain a subset of your object's actual properties. You only need to map the values that are supposed to change under the initial value problem.\n- `abTypes.valueObject<T, P>(ctor: (props: P) => T, description: ValueObjectDescription<T, P>): ABType<T>`: Similar to `object`, but instead of writing directly to properties of your objects, this `ABType` creates new objects from the described properties using the provided constructor. Values are read using the provided property accessors.\n- `abTypes.array<T>(itemType: ABType<T>, fixedLength?: number): ABType<T[]>`: Takes an array-backed type and returns the corresponding array-backed array type. The optional `fixedLength` parameter can be used to help out with calculating the required host array's length. The size of your objects are anyway not supposed to change during derivative evaluations, but it might change from one step to the next. If the `fixedLength` parameter is omitted, the host array's length will be determined dynamically.\n\nSuppose you want to interface with the 3D library `threejs` and you modeled bodies with a type like this:\n\n```typescript\nimport { Vector3 } from \"three\";\n\n\ninterface Body {\n  mass: number;\n  position: Vector3;\n  velocity: Vector3;\n  force: Vector3;\n  // ...\n}\n```\n\nThe corresponding array-backed types can be created like so:\n\n```typescript\nimport { abTypes } from \"@b3gm/ode-to-joy\";\n\n\nconst arrayBackedVector: ABType<Vector3> = abTypes.object({\n  x: abTypes.float(),\n  y: abTypes.float(),\n  z: abTypes.float()\n});\n\nconst arrayBackedBody: ABType<Body> = abTypes.object({\n  // mass and force fields can be omitted, if they are not supposed to be \n  // integrated over time.\n  position: arrayBackedVector,\n  velocity: arrayBackedVector\n});\n\nconst arrayBackedBodyArray: ABType<Body[]> = abTypes.array(arrayBackedBody);\n```\n\nNow with `arrayBackedBodyArray`, which represents the set of bodies that compose your physical system, you can use `createGenericExplicitSolver` and a derivative function written in the `Body` domain to evolve your system over time:\n\n```typescript\nimport {\n  createGenericExplicitSolver,\n  explicitSolvers\n} from \"@b3gm/ode-to-joy\";\n\n\nconst system: Body[] = /* construct initial system */;\nconst systemSolver = createGenericExplicitSolver({\n  itemType: arrayBackedBodyArray,\n  solver: explicitSolvers.rungeKutta4\n})((bodies: Body[]) => {\n  // usually start by resetting all forces or initializing them with externals.\n  bodies.forEach((body) => body.force.set(0, 0, 0));\n\n  // Calculate the derivative of bodies' fields by evaluating exchange forces.\n  // This depends on the nature of your model, so this is left as an exercise\n  // to the reader ;o)\n\n  bodies.forEach((body) => {\n    // The derivative of the position is velocity\n    body.position.copy(body.velocity);\n    // and the derivative of velocity is acceleration.\n    body.velocity.copy(body.force.divideScalar(body.mass));\n  });\n  return bodies; // either return the modified system, or a new value.\n});\n\n// the exact value for the step size again depends on the nature of your model\n// if forces are calculated on the basis of time in milliseconds and you need\n// 60 frames per second you would advance your system like this. Usually called\n// from within a requestAnimationFrame loop:\nsystemSolver(bodies)(1000/60);\n```\n","readmeFilename":"README.md"}