{"id":24865137,"url":"https://github.com/diku-dk/rainbow","last_synced_at":"2025-10-15T09:32:21.600Z","repository":{"id":43942019,"uuid":"457357082","full_name":"diku-dk/RAINBOW","owner":"diku-dk","description":"Software modules for modelling and simulation","archived":false,"fork":false,"pushed_at":"2025-01-24T11:10:19.000Z","size":33744,"stargazers_count":9,"open_issues_count":6,"forks_count":2,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-01-24T12:20:29.857Z","etag":null,"topics":["computational-mechanics","mesh-generation","mesh-processing","meshing","meshing-algorithms","modeling","numerical-methods","rigid-body-dynamics","simulation","softbody-dynamics"],"latest_commit_sha":null,"homepage":"https://diku-dk.github.io/RAINBOW/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diku-dk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-09T12:52:12.000Z","updated_at":"2025-01-08T12:25:21.000Z","dependencies_parsed_at":"2024-01-12T04:51:47.730Z","dependency_job_id":"107b251f-eded-4e74-9b43-d4610e9f8da7","html_url":"https://github.com/diku-dk/RAINBOW","commit_stats":{"total_commits":192,"total_committers":7,"mean_commits":"27.428571428571427","dds":0.6666666666666667,"last_synced_commit":"b20f5d155927c5138151cd5d2851d0edcd69fb73"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diku-dk%2FRAINBOW","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diku-dk%2FRAINBOW/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diku-dk%2FRAINBOW/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diku-dk%2FRAINBOW/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diku-dk","download_url":"https://codeload.github.com/diku-dk/RAINBOW/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236600339,"owners_count":19175173,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computational-mechanics","mesh-generation","mesh-processing","meshing","meshing-algorithms","modeling","numerical-methods","rigid-body-dynamics","simulation","softbody-dynamics"],"created_at":"2025-01-31T23:57:47.622Z","updated_at":"2025-10-15T09:32:19.124Z","avatar_url":"https://github.com/diku-dk.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RAINBOW Software Foundation (RAINBOW)\n\n\n\n\n## Rigid Body Examples\n\n### Imports\nFirst import the modules\n\n```python\nimport numpy as np\nimport rainbow.math.vector3 as V3\nimport rainbow.math.quaternion as Q\nimport rainbow.simulators.prox_rigid_bodies.api as API\nimport rainbow.simulators.prox_rigid_bodies.scenes as SCENE\nfrom rainbow.geometry.surface_mesh import create_sphere, create_box\n```\n\n### Examples 1 - Get started\nLet's make a box rotate 360 degrees by setting its angular velocity to 2 pi and run the simulation for a second.  \n\nStart by creating an environment. In this case, we create a box with dimensions 5., 5. and 10. \n\n```python\nengine = API.Engine()\n\nAPI.create_rigid_body(engine,'box_body')\n\nV, T   = create_box(5.,5., 10.) \n\nmesh = API.create_mesh(V, T)\nAPI.create_shape(engine, 'box_shape', mesh )\nAPI.connect_shape(engine, 'box_body', 'box_shape')\n```\n\nLet's set the mass and the angular velocity. \n\n```python\nAPI.set_mass_properties(engine,'box_body', 1)\nAPI.set_spin(engine, 'box_body', V3.make(2.*np.pi, 0., 0.))\n```\n\nFinally, simulate over time by creating a simulation loop.\n\n```python\ndef simulation(viewer, engine, monitor=True) -\u003e None:\n    dt = engine.params.time_step\n    T  = engine.params.total_time \n    fps = 1.0/dt\n    steps = int(np.round(T*fps))\n    for i in range(steps):\n        for body in engine.bodies.values():\n            # Update any visualization of the rigid body\n            ...\n        API.simulate(engine, dt, monitor)\n\nengine.params.total_time = 1 #sec       \nsimulation(viewer, engine, True)\n```\n\n### Example 2 - Interactions\nLet's create a simulation with a simple interaction. Thus we initialize two spheres. Next, we force the spheres to collide by setting their initial velocity opposite each other.  \n\nFirst, create an environment as before. \n\n```python\nengine = API.Engine()\nAPI.create_rigid_body(engine,'sphere_body_1')\nAPI.create_rigid_body(engine,'sphere_body_2')\n\nV_1, T_1 = create_sphere(5.0,16,16)\nV_2, T_2 = create_sphere(5.0,16,16)\n\nmesh_1 = API.create_mesh(V_1, T_1)\nmesh_2 = API.create_mesh(V_2, T_2)\n\nAPI.create_shape(engine, 'sphere_shape_1', mesh_1)\nAPI.create_shape(engine, 'sphere_shape_2', mesh_2)\n\nAPI.connect_shape(engine, 'sphere_body_1', 'sphere_shape_1')\nAPI.connect_shape(engine, 'sphere_body_2', 'sphere_shape_2')\n\nAPI.set_mass_properties(engine,'sphere_body_1', 1)\nAPI.set_mass_properties(engine,'sphere_body_2', 1)\n\nAPI.set_position(engine, 'sphere_body_1', V3.make( 55.0, 0.0,0.0), use_model_frame=True)\nAPI.set_position(engine, 'sphere_body_2', V3.make(-55.0, 0.0,0.0), use_model_frame=True)\n\nAPI.set_velocity(engine, 'sphere_body_1', V3.make( -100., 0., 0.))\nAPI.set_velocity(engine, 'sphere_body_2', V3.make(  100., 0., 0.))\n```\n\nThe materials of the spheres have an elasticity factor of 0.5. (An object has \"default\" as material as default.)\n\n```python\ntest_material = \"material\"\nAPI.create_surfaces_interaction(engine, test_material, test_material, 0.5, V3.make(np.inf, np.inf, np.inf))\nAPI.set_body_material(engine, 'sphere_body_1', test_material)\nAPI.set_body_material(engine, 'sphere_body_2', test_material)\nengine.params.use_bounce = True\n```\n\nSimulate as before.\n\n```python\ndef simulation(viewer, engine, monitor=True) -\u003e None:\n    dt = engine.params.time_step\n    T  = engine.params.total_time \n    fps = 1.0/dt\n    steps = int(np.round(T*fps))\n    for i in range(0, steps+1):\n        for body in engine.bodies.values():\n            # Update visualization of body\n            ...\n        API.simulate(engine, dt, monitor)\n\nengine.params.total_time = 1 #sec \nengine.params.time_step  = 0.01\nsimulation(viewer, engine, True)\n```\n\n### Example 3 - Use the force\nThis tutorial shows how to add forces such as gravitational force. \n\nFirst, initialize the environment. \n\n```python\nengine = API.Engine()\nSCENE.create_ground(engine, V3.zero(), Q.Rx(0.3*np.pi), density=1000.0, material_name='default');\n\nAPI.create_rigid_body(engine,'sphere_body')\n\nV_1, T_1 = create_sphere(5.0,16,16)\n\nmesh_1 = API.create_mesh(V_1, T_1)\n\nAPI.create_shape(engine, 'sphere_shape', mesh_1)\n\nAPI.connect_shape(engine, 'sphere_body', 'sphere_shape')\n\nAPI.set_mass_properties(engine,'sphere_body', 1/504) # Creates an mass of 1\n\nv0  = V3.make(10.0, 10.,0 )\nx0  = V3.make( -40.0, 30.0,0.0)\ndirection_vector = V3.make(0.,1.,0.)\ngravity_force     = 0.1\n\nAPI.set_position(engine, 'sphere_body', x0, use_model_frame=True)\nAPI.set_velocity(engine, 'sphere_body', v0)\n\nAPI.create_gravity_force(engine, 'gravity_f', gravity_force, direction_vector)\nAPI.connect_force(engine, 'sphere_body', 'gravity_f')\n```\n\nThe simulation is as before.\n\n### Example 4 - Friction\nLet's make a sliding box to illustrate how friction works.\n\nSetup the environment,\n\n```python\nengine = API.Engine()\n\nmu_x     = -0.1*np.pi\nmu_y     = 0.0\nmu_z     = 0.0\n\nv_mu    = V3.make(mu_x, mu_y, mu_z)\nq_mu   = Q.Rx(mu_x)\nsize = 6.0 \n\ntest_material = \"material\"\nAPI.create_surfaces_interaction(engine, test_material, test_material, 1, np.arctan(V3.make((0.09*np.pi), np.inf, np.inf)))\n\nSCENE.create_ground(engine, V3.zero(), q_mu, density=1000.0, material_name=test_material)\nAPI.create_rigid_body(engine,'sphere_body')\n\nV_1, T_1 = create_box(size, size, size)\n\nmesh_1 = API.create_mesh(V_1, T_1)\n\nAPI.create_shape(engine, 'sphere_shape', mesh_1)\n\nAPI.connect_shape(engine, 'sphere_body', 'sphere_shape')\n\nrx  = Q.Rx(mu_x)\npos = Q.rotate(rx, V3.make(0.0, size / 2,0.0))\n\ndirection_vector = V3.make(0.,1.,0.)\ngravity_force     = 0.1\n\nAPI.set_position(engine, 'sphere_body', pos, use_model_frame=True)\nAPI.set_orientation(engine, 'sphere_body', rx, use_model_frame=True)\nAPI.set_mass_properties(engine,'sphere_body', 1)\n\nAPI.create_gravity_force(engine, 'gravity_f', gravity_force, direction_vector)\nAPI.connect_force(engine, 'sphere_body', 'gravity_f')\n\n\nAPI.set_body_material(engine, 'sphere_body', test_material)\nengine.params.use_bounce = True\n```\n\nNow simulate as before.\n\n### Analyse the friction simulation example\n\nUse the get_log function:\n\n```python\nstats = API.get_log(engine)\n```\n\nPlot convergence.\n\n```python\nimport matplotlib.pyplot as plt\ncolors = ['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4',\n          '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff',\n          '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1',\n          '#000075', '#808080', '#ffffff', '#000000']\nfig = plt.figure()\nax = plt.subplot(111)\nax.set_title('Convergence rates')\nax.set_xlabel('Iterations')\nax.set_ylabel('Merit')\nplt.grid(True)\nfor i in range(len(stats)):\n    data = stats[i]\n    if 'residuals' in data.keys():\n        residuals = data['residuals']\n        reject = data['reject']\n        ax.plot( residuals[np.where(reject==False)])\nplt.show()\n```\nProfile the simulation.\n\n```python\ntime_update_bvh = [ stats[i]['update_bvh'] for i in range(len(stats)) ]\ntime_narrow_phase = [ stats[i]['narrow_phase'] for i in range(len(stats)) ]\ntime_contact_determination = [ stats[i]['contact_determination'] for i in range(len(stats)) ]\ntime_contact_point_reduction = [ stats[i]['contact_point_reduction'] for i in range(len(stats)) ]\ntime_collision_detection = [ stats[i]['collision_detection_time'] for i in range(len(stats)) ]\n\ntime_stepper = [ stats[i]['stepper_time'] for i in range(len(stats)) ]\n\n\nfig = plt.figure()\nax = plt.subplot(111)\nax.set_title('Profiling Timings')\nax.set_xlabel('Step')\nax.set_ylabel('Time [s]')\nplt.grid(True)\nax.plot(time_update_bvh, label='Update bvh', color=colors[6])\nax.plot(time_narrow_phase, label='Narrow phase', color=colors[7])\nax.plot(time_contact_determination, label='Contact determination', color=colors[8])\nax.plot(time_contact_point_reduction, label='Contact reduction', color=colors[9])\nax.plot(time_collision_detection, label='Collision Detection', color=colors[10])\nax.plot(time_stepper, label='Stepper', color=colors[11])\nax.legend()\nplt.show()\n\nnumber_of_overlaps = [ stats[i]['number_of_overlaps'] for i in range(1, len(stats)) ]\nstep_sizes = [ stats[i]['dt'] for i in range(1, len(stats)) ]\nnumber_of_contact_points = [ stats[i]['contact_points'] for i in range(1, len(stats)) ]\npenetrations = [ stats[i]['max_penetration'] for i in range(1, len(stats)) ]\n\nfig = plt.figure()\nax = plt.subplot(111)\nax.set_title('Profiling data')\nax.set_xlabel('Step')\nax.set_ylabel('Value')\nplt.grid(True)\nax.plot(number_of_overlaps, label='Overlaps', color=colors[0])\nax.plot(step_sizes, label='Stepsize', color=colors[1])\nax.plot(number_of_contact_points, label='Contacts', color=colors[2])\nax.plot(penetrations, label='Penetrations', color=colors[6])\nax.legend()\nplt.show()\n```\nShow the potential energy and the kinetic energy.\n\n```python\nkinetic_energy = [ stats[i]['kinetic_energy'] for i in range(len(stats)) ]\npotential_energy = [ stats[i]['potential_energy'] for i in range(len(stats)) ]\n\nfig = plt.figure()\nax = plt.subplot(111)\nax.set_title('Energy Plots')\nax.set_xlabel('Step')\nax.set_ylabel('Value')\nplt.grid(True)\nax.plot(kinetic_energy, label='Kinetic Energy', color=colors[4])\nax.plot(potential_energy, label='Potential Energy', color=colors[5])\nax.legend()\nplt.show()\n```\n\n### Example 5 - Advanced Shapes\nLet's make a sliding box to illustrate how friction. In the last example, we create a more advanced shape using the procedural module. \n\n```python\nengine = API.Engine()\nSCENE.create_ground(engine, V3.zero(), Q.identity(), density=1000.0, material_name='default');\nSCENE.create_dome(engine,\n                 r = V3.zero(),\n                 q = Q.identity(),\n                 outer_radius = 5.0,\n                 inner_radius = 4.0,\n                 layers = 4,\n                 segments = 11,\n                 density = 1.0,\n                 material_name = 'default'\n                )\n```\nSimulate as before.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiku-dk%2Frainbow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiku-dk%2Frainbow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiku-dk%2Frainbow/lists"}