diff --git a/.gitignore b/.gitignore index 49c5b20..52bf6f2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__ tmp/* src/web_app/cache /benchmark/ +src/web_app/images diff --git a/Dockerfile b/Dockerfile index 6796519..cafef09 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,11 @@ RUN pip install --upgrade pip COPY requirements.txt requirements.txt RUN pip install -r requirements.txt COPY src/ src +COPY run_webpage.py run_webpage.py COPY configuration/ configuration COPY resources/ resources -ENV PYTHONPATH "${PYTHONPATH}:src/.:src/web_app/.:src/sim/." +#ENV PYTHONPATH "${PYTHONPATH}:src/.:src/web_app/.:src/sim/." -CMD ["python", "src/web_app/index.py"] \ No newline at end of file +#CMD ["python", "src/web_app/index.py"] +CMD ["python", "run_webpage.py"] \ No newline at end of file diff --git a/README.md b/README.md index 441a9d1..85ca6c2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,145 @@ # Simulator Automatic Warehouse -This repository is a thesis project for University of Verona (Università di Verona).\ -\ -This project allows to simulate an automatic warehouse by inserting some information like: height, weight, etc.\ -Furthermore, you can visit a webpage (index.py) to create new simulations in a user-friendly way.\ -\ -The project is "in progress", so the documentation will come soon... +This repository was created for a thesis project for the University of Verona (Università di Verona). + +The project is a simulator of an automatic warehouse. The inspiration came from the [Vertimag][1] of +[Ferretto Group][2], an Italian company based in Vicenza. +So the logic of the warehouse digitalized is the same of the real Vertimag. + +As a case study, the Vertimag present in the [ICE Laboratory][3] was chosen. +The warehouse you'll find is made for education/research purposes, so it's different from a classic Vertimag +that you can find in the industries (see the differences in these photos: [ICELab Vertimag][4] and [Industries Vertimag][1]). +However, this does not mean that the project is not valid! +In fact, the project is used as a base by the researchers at the ICELab to make another simulator using different +technologies. + +The repository contains a `src` directory where you can find: the **simulator** and the **webpage**. + +The simulator is mainly made using [SimPy v4.0.2][5] and simulates 4 actions (you can implement more if you need to). +The webpage is made using [Dash v2.15.0][6] (with the support of [Dash Bootstrap Components v1.5.0][7]) and +[Plotly v5.17.0][8] to allow the end-user, in this case the thesis advisor, +to interact with the simulator in a user-friendly way. + +In the future, you need to add unittest. + +------------------------------------------------------------------------------------------------------------------------ + +## How to Install and Run the Project + +You can choose to run the project in one of two ways: using [Python v3.12.2][9] or using [Docker][10] +and [Docker compose][13]. + +### Python + +Install the requirements using [pip][11]: + +```bash +pip install -r requirements.txt +``` + +#### Simulator + +To run only the simulator without the webpage, go to the project directory simulator-automatic-warehouse +and set the environment variable for the configuration. +Each simulation uses a yaml file to set up the automatic warehouse +(a full explanation of the config file can be found in +[configuration/sample_config.yaml](configuration/sample_config.yaml): + +```bash +export WAREHOUSE_CONFIGURATION_FILE_PATH=configuration/univr/ICE_lab.yaml +python3.12 run_simulator.py +``` + +Or one line: + +```bash +WAREHOUSE_CONFIGURATION_FILE_PATH=configuration/univr/ICE_lab.yaml python3.12 run_simulator.py +``` + +The loaded configuration represents the Vertimag in ICELab. +You can create another configuration following the json schema +([resources/configuration/json_schema.json](resources/configuration/json_schema.json)). + +Finally, it's possible to manage the console log using the environment variables: + - `NO_CONSOLE_LOG`: If set, console logs are not displayed. + - `DEBUG_LOG`: if set, debug logging will be printed to the console. + - `FILENAME_DEBUG_LOG`: if set, save the debug log to file (e.g. `sim.log`). + +#### Website + +To run the website, in addition to the environment variables specified in the [Simulator](#simulator) section, +you need to specify: + - HOST: Host IP used to serve the application. + - PORT: Port used to serve the application. + - (optional) PROXY: If this application will be served to a different URL via a proxy configured outside of Python, + you can list it here as a string of the form `{input}::{output}`, for example: + `http://0.0.0.0:8050::https://my.domain.com` + so that the startup message will display an accurate URL. + +For example, in localhost: + +```bash +export WAREHOUSE_CONFIGURATION_FILE_PATH=configuration/univr/ICE_lab.yaml +export HOST=127.0.0.1 +export PORT=8050 +python3.12 run_webpage.py +``` + +**Note**: +the username and password to access at the page can be found in the [`index.py`](src/web_app/index.py) file +after the `app` variable declaration. +The default, the values are: + +```python +USER_PWD = { + "admin": "admin" +} +``` + +But you can specify other users (see the complete documentation: [Dash Authentication][12]). + +### Docker + +Everything is easier with Docker. Go to the [docker](docker) folder and use docker compose to build: + +```bash +cd docker && docker compose up +``` + +If you want to change or add some environment variables, edit [docker-compose.yaml](docker/docker-compose.yaml). + +------------------------------------------------------------------------------------------------------------------------ + +## Benchmarks + +Here are some benchmarks run with a private Python library and the following computer specifications: + - Intel i7-8750H + - SDRAM DDR4-2666 16GB + - MZ-76Q2T0 860 QVO SSD 2TB 2.5" + - SSD NVMe M.2 128 GB + - NVIDIA GeForce GTX 1050 + +| Actions | Time to process | Real-time simulation | +|-----------|-----------------|----------------------| +| 10'000 | 1 second | 1d. 2h. 48m. | +| 63'000 | 7.5 seconds | 1 week | +| 267'900 | 25 seconds | 1 month | +| 3'250'120 | 9 minutes | 1 year | + +Relationship between simulated actions and media + +Standard deviation + +[1]: https://www.ferrettogroup.com/index.cfm/en/solutions/vertical-storage-system/vertical-lift-module-vertimag/ +[2]: https://www.ferrettogroup.com/index.cfm/en/ +[3]: https://www.icelab.di.univr.it/ +[4]: https://icewebsitestorage.blob.core.windows.net/icewebsitemediablob/gallery/IMG_0855.JPG +[5]: https://simpy.readthedocs.io/en/4.0.2/ +[6]: https://dash.plotly.com/ +[7]: https://dash-bootstrap-components.opensource.faculty.ai/ +[8]: https://plotly.com/python/ +[9]: https://www.get-python.org/downloads/release/python-3122/ +[10]: https://docs.docker.com/engine/ +[11]: https://pip.pypa.io/en/stable/getting-started/ +[12]: https://dash.plotly.com/authentication +[13]: https://docs.docker.com/compose/ \ No newline at end of file diff --git a/resources/doc/relationship_between_simulated_actions_and_media.svg b/resources/doc/relationship_between_simulated_actions_and_media.svg new file mode 100644 index 0000000..4538857 --- /dev/null +++ b/resources/doc/relationship_between_simulated_actions_and_media.svg @@ -0,0 +1 @@ +050010001500200025003000350050250100020003000400050006000700080009000100001100012000130001400015000160001700018000190002000021000220002300024000MillisecondsActions simulatedRelationship between simulated actions and mediaMean (ms) \ No newline at end of file diff --git a/resources/doc/standard_deviation.svg b/resources/doc/standard_deviation.svg new file mode 100644 index 0000000..6528551 --- /dev/null +++ b/resources/doc/standard_deviation.svg @@ -0,0 +1 @@ +0500100015002000250030003500050001000015000200002500030000MillisecondsActions simulatedStandard DeviationMean (ms)StdDev (ms) \ No newline at end of file diff --git a/run_simulator.py b/run_simulator.py new file mode 100644 index 0000000..5ef79cd --- /dev/null +++ b/run_simulator.py @@ -0,0 +1,4 @@ +from src.sim.__main__ import run_simulator + +if __name__ == '__main__': + run_simulator() diff --git a/run_webpage.py b/run_webpage.py new file mode 100644 index 0000000..0e32663 --- /dev/null +++ b/run_webpage.py @@ -0,0 +1,4 @@ +from src.web_app.index import run_webpage + +if __name__ == "__main__": + run_webpage() diff --git a/simulation_algorithm.jpg b/simulation_algorithm.jpg deleted file mode 100644 index 9897e28..0000000 Binary files a/simulation_algorithm.jpg and /dev/null differ diff --git a/src/sim/__main__.py b/src/sim/__main__.py index c94b4f3..364bb56 100644 --- a/src/sim/__main__.py +++ b/src/sim/__main__.py @@ -1,7 +1,7 @@ -from sim.warehouse import Warehouse +from src.sim.warehouse import Warehouse -if __name__ == "__main__": +def run_simulator(): # debug purpose # import random # random.seed(None) @@ -10,7 +10,7 @@ (warehouse := Warehouse()).run_simulation() # save the configuration at the end - # from sim.utils.save_warehouse_state import save_config + # from src.sim.utils.save_warehouse_state import save_config # save_config(warehouse.get_simulation().get_warehouse()) diff --git a/src/sim/drawer.py b/src/sim/drawer.py index ce716da..62285d0 100644 --- a/src/sim/drawer.py +++ b/src/sim/drawer.py @@ -1,8 +1,8 @@ import copy import random -from sim.material import Material -from sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton +from src.sim.material import Material +from src.sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton class Drawer: diff --git a/src/sim/material.py b/src/sim/material.py index daea211..3eeda9c 100644 --- a/src/sim/material.py +++ b/src/sim/material.py @@ -1,6 +1,6 @@ import random import uuid -from sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton +from src.sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton class Material: diff --git a/src/sim/simulation.py b/src/sim/simulation.py index e7d42d1..de69e7e 100644 --- a/src/sim/simulation.py +++ b/src/sim/simulation.py @@ -3,16 +3,11 @@ import simpy from simpy import Environment -from sim.warehouse import Warehouse +from src.sim.warehouse import Warehouse logger = logging.getLogger(__name__) -# -----: send_back prende dalla baia il drawer e lo manda all'interno del magazzino usando Move -# -----: extract_drawer prende un cassetto dentro il magazzino e lo mette nel carousel -# -----: GoToDeposit viene forzata dopo ogni operazione per ritornare al punto di partenza -# -----: InsertMaterial classe abs che ha come figli InsertRandomMaterial e InsertMaterial - class Simulation: def __init__(self, env: Environment, warehouse: Warehouse): @@ -26,13 +21,13 @@ def __init__(self, env: Environment, warehouse: Warehouse): self.store_history = None def simulate_actions(self, events_generated: list): - from sim.status_warehouse.enum_warehouse import EnumWarehouse - from sim.status_warehouse.simulate_events.buffer import Buffer - from sim.status_warehouse.simulate_events.send_back_drawer import SendBackDrawer - from sim.status_warehouse.simulate_events.extract_drawer import ExtractDrawer - from sim.status_warehouse.simulate_events.material.insert_material.insert_random_material \ + from src.sim.status_warehouse.enum_warehouse import EnumWarehouse + from src.sim.status_warehouse.simulate_events.buffer import Buffer + from src.sim.status_warehouse.simulate_events.send_back_drawer import SendBackDrawer + from src.sim.status_warehouse.simulate_events.extract_drawer import ExtractDrawer + from src.sim.status_warehouse.simulate_events.material.insert_material.insert_random_material \ import InsertRandomMaterial - from sim.status_warehouse.simulate_events.material.remove_material.remove_random_material \ + from src.sim.status_warehouse.simulate_events.material.remove_material.remove_random_material \ import RemoveRandomMaterial self.store_history = simpy.Store(self.get_environment(), capacity=len(events_generated)) diff --git a/src/sim/status_warehouse/container/carousel.py b/src/sim/status_warehouse/container/carousel.py index f0603f6..1f924e4 100644 --- a/src/sim/status_warehouse/container/carousel.py +++ b/src/sim/status_warehouse/container/carousel.py @@ -1,9 +1,9 @@ import copy -from sim.drawer import Drawer -from sim.status_warehouse.container.drawer_container import DrawerContainer -from sim.status_warehouse.entry.drawer_entry import DrawerEntry -from sim.status_warehouse.entry.empty_entry import EmptyEntry +from src.sim.drawer import Drawer +from src.sim.status_warehouse.container.drawer_container import DrawerContainer +from src.sim.status_warehouse.entry.drawer_entry import DrawerEntry +from src.sim.status_warehouse.entry.empty_entry import EmptyEntry class Carousel(DrawerContainer): diff --git a/src/sim/status_warehouse/container/column.py b/src/sim/status_warehouse/container/column.py index 501f08b..b9839e1 100644 --- a/src/sim/status_warehouse/container/column.py +++ b/src/sim/status_warehouse/container/column.py @@ -1,9 +1,9 @@ import copy -from sim.drawer import Drawer -from sim.status_warehouse.container.drawer_container import DrawerContainer -from sim.status_warehouse.entry.drawer_entry import DrawerEntry -from sim.status_warehouse.entry.empty_entry import EmptyEntry +from src.sim.drawer import Drawer +from src.sim.status_warehouse.container.drawer_container import DrawerContainer +from src.sim.status_warehouse.entry.drawer_entry import DrawerEntry +from src.sim.status_warehouse.entry.empty_entry import EmptyEntry class Column(DrawerContainer): diff --git a/src/sim/status_warehouse/container/drawer_container.py b/src/sim/status_warehouse/container/drawer_container.py index a61bc31..16375b4 100644 --- a/src/sim/status_warehouse/container/drawer_container.py +++ b/src/sim/status_warehouse/container/drawer_container.py @@ -1,9 +1,9 @@ from abc import abstractmethod -from sim.drawer import Drawer -from sim.status_warehouse.entry.drawer_entry import DrawerEntry -from sim.status_warehouse.entry.empty_entry import EmptyEntry -from sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton +from src.sim.drawer import Drawer +from src.sim.status_warehouse.entry.drawer_entry import DrawerEntry +from src.sim.status_warehouse.entry.empty_entry import EmptyEntry +from src.sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton class DrawerContainer: diff --git a/src/sim/status_warehouse/entry/drawer_entry.py b/src/sim/status_warehouse/entry/drawer_entry.py index e2bcc58..aebab70 100644 --- a/src/sim/status_warehouse/entry/drawer_entry.py +++ b/src/sim/status_warehouse/entry/drawer_entry.py @@ -1,7 +1,7 @@ import copy -from sim.drawer import Drawer -from sim.status_warehouse.entry.entry import Entry +from src.sim.drawer import Drawer +from src.sim.status_warehouse.entry.entry import Entry class DrawerEntry(Entry): diff --git a/src/sim/status_warehouse/entry/empty_entry.py b/src/sim/status_warehouse/entry/empty_entry.py index 96cc92a..298201d 100644 --- a/src/sim/status_warehouse/entry/empty_entry.py +++ b/src/sim/status_warehouse/entry/empty_entry.py @@ -1,4 +1,4 @@ -from sim.status_warehouse.entry.entry import Entry +from src.sim.status_warehouse.entry.entry import Entry class EmptyEntry(Entry): diff --git a/src/sim/status_warehouse/simulate_events/action.py b/src/sim/status_warehouse/simulate_events/action.py index 37be195..3a22384 100644 --- a/src/sim/status_warehouse/simulate_events/action.py +++ b/src/sim/status_warehouse/simulate_events/action.py @@ -2,8 +2,7 @@ from simpy import Environment -# from src.simulation import Floor -from sim.warehouse import Warehouse +from src.sim.warehouse import Warehouse class Action: diff --git a/src/sim/status_warehouse/simulate_events/buffer.py b/src/sim/status_warehouse/simulate_events/buffer.py index 3391f5a..8d42bd9 100644 --- a/src/sim/status_warehouse/simulate_events/buffer.py +++ b/src/sim/status_warehouse/simulate_events/buffer.py @@ -3,9 +3,9 @@ from simpy import Environment # from src.drawer import Drawer -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.action import Action -from sim.warehouse import Warehouse +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.action import Action +from src.sim.warehouse import Warehouse logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/extract_drawer.py b/src/sim/status_warehouse/simulate_events/extract_drawer.py index 5ae872d..a7c57c4 100644 --- a/src/sim/status_warehouse/simulate_events/extract_drawer.py +++ b/src/sim/status_warehouse/simulate_events/extract_drawer.py @@ -3,15 +3,15 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.buffer import Buffer -from sim.status_warehouse.simulate_events.move.go_to_deposit import GoToDeposit -from sim.status_warehouse.simulate_events.move.go_to_buffer import GoToBuffer -from sim.status_warehouse.simulate_events.move.move import Move -from sim.status_warehouse.simulate_events.move.unload import Unload -from sim.status_warehouse.simulate_events.move.vertical import Vertical -from sim.warehouse import Warehouse # , Drawer -from sim.status_warehouse.simulate_events.action_enum import ActionEnum +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.buffer import Buffer +from src.sim.status_warehouse.simulate_events.move.go_to_deposit import GoToDeposit +from src.sim.status_warehouse.simulate_events.move.go_to_buffer import GoToBuffer +from src.sim.status_warehouse.simulate_events.move.move import Move +from src.sim.status_warehouse.simulate_events.move.unload import Unload +from src.sim.status_warehouse.simulate_events.move.vertical import Vertical +from src.sim.warehouse import Warehouse # , Drawer +from src.sim.status_warehouse.simulate_events.action_enum import ActionEnum logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/material/insert_material/insert_manual_material.py b/src/sim/status_warehouse/simulate_events/material/insert_material/insert_manual_material.py index a694290..645c043 100644 --- a/src/sim/status_warehouse/simulate_events/material/insert_material/insert_manual_material.py +++ b/src/sim/status_warehouse/simulate_events/material/insert_material/insert_manual_material.py @@ -1,10 +1,10 @@ from simpy import Environment # from src.drawer import Drawer -from sim.material import Material -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.material.insert_material.insert_material import InsertMaterial -from sim.warehouse import Warehouse +from src.sim.material import Material +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.material.insert_material.insert_material import InsertMaterial +from src.sim.warehouse import Warehouse class InsertManualMaterial(InsertMaterial): diff --git a/src/sim/status_warehouse/simulate_events/material/insert_material/insert_material.py b/src/sim/status_warehouse/simulate_events/material/insert_material/insert_material.py index 5efab5e..0cf4f42 100644 --- a/src/sim/status_warehouse/simulate_events/material/insert_material/insert_material.py +++ b/src/sim/status_warehouse/simulate_events/material/insert_material/insert_material.py @@ -4,9 +4,9 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.action import Action -from sim.warehouse import Warehouse +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.action import Action +from src.sim.warehouse import Warehouse logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/material/insert_material/insert_random_material.py b/src/sim/status_warehouse/simulate_events/material/insert_material/insert_random_material.py index fd16ab2..b3c5009 100644 --- a/src/sim/status_warehouse/simulate_events/material/insert_material/insert_random_material.py +++ b/src/sim/status_warehouse/simulate_events/material/insert_material/insert_random_material.py @@ -1,10 +1,10 @@ from simpy import Environment import datetime -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.material.insert_material.insert_material import InsertMaterial -from sim.warehouse import Warehouse -from sim.status_warehouse.simulate_events.action_enum import ActionEnum +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.material.insert_material.insert_material import InsertMaterial +from src.sim.warehouse import Warehouse +from src.sim.status_warehouse.simulate_events.action_enum import ActionEnum class InsertRandomMaterial(InsertMaterial): @@ -13,7 +13,7 @@ def __init__(self, env: Environment, warehouse: Warehouse, simulation: Simulatio # override def simulate_action(self): - from sim.material import gen_rand_material + from src.sim.material import gen_rand_material start_time = datetime.datetime.now() + datetime.timedelta(seconds=self.get_env().now) diff --git a/src/sim/status_warehouse/simulate_events/material/remove_material/remove_manual_material.py b/src/sim/status_warehouse/simulate_events/material/remove_material/remove_manual_material.py index 9ad98cc..9533de9 100644 --- a/src/sim/status_warehouse/simulate_events/material/remove_material/remove_manual_material.py +++ b/src/sim/status_warehouse/simulate_events/material/remove_material/remove_manual_material.py @@ -3,10 +3,10 @@ from simpy import Environment # from src.drawer import Drawer -from sim.material import Material -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.material.remove_material.remove_material import RemoveMaterial -from sim.warehouse import Warehouse +from src.sim.material import Material +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.material.remove_material.remove_material import RemoveMaterial +from src.sim.warehouse import Warehouse logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/material/remove_material/remove_material.py b/src/sim/status_warehouse/simulate_events/material/remove_material/remove_material.py index 5b34664..72544e5 100644 --- a/src/sim/status_warehouse/simulate_events/material/remove_material/remove_material.py +++ b/src/sim/status_warehouse/simulate_events/material/remove_material/remove_material.py @@ -4,9 +4,9 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.action import Action -from sim.warehouse import Warehouse +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.action import Action +from src.sim.warehouse import Warehouse logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/material/remove_material/remove_random_material.py b/src/sim/status_warehouse/simulate_events/material/remove_material/remove_random_material.py index 4bd17fa..403b9a9 100644 --- a/src/sim/status_warehouse/simulate_events/material/remove_material/remove_random_material.py +++ b/src/sim/status_warehouse/simulate_events/material/remove_material/remove_random_material.py @@ -2,10 +2,10 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.material.remove_material.remove_material import RemoveMaterial -from sim.warehouse import Warehouse -from sim.status_warehouse.simulate_events.action_enum import ActionEnum +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.material.remove_material.remove_material import RemoveMaterial +from src.sim.warehouse import Warehouse +from src.sim.status_warehouse.simulate_events.action_enum import ActionEnum logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/move/go_to_buffer.py b/src/sim/status_warehouse/simulate_events/move/go_to_buffer.py index 3a785ce..02c0f74 100644 --- a/src/sim/status_warehouse/simulate_events/move/go_to_buffer.py +++ b/src/sim/status_warehouse/simulate_events/move/go_to_buffer.py @@ -2,10 +2,10 @@ from simpy import Environment -from sim.drawer import Drawer -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.move.move import Move -from sim.warehouse import Warehouse +from src.sim.drawer import Drawer +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.move.move import Move +from src.sim.warehouse import Warehouse logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/move/go_to_deposit.py b/src/sim/status_warehouse/simulate_events/move/go_to_deposit.py index e577f96..ac70919 100644 --- a/src/sim/status_warehouse/simulate_events/move/go_to_deposit.py +++ b/src/sim/status_warehouse/simulate_events/move/go_to_deposit.py @@ -2,11 +2,11 @@ from simpy import Environment -from sim.drawer import Drawer +from src.sim.drawer import Drawer # from src.drawer import Drawer -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.move.move import Move -from sim.warehouse import Warehouse +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.move.move import Move +from src.sim.warehouse import Warehouse logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/move/load.py b/src/sim/status_warehouse/simulate_events/move/load.py index 5452efa..6815844 100644 --- a/src/sim/status_warehouse/simulate_events/move/load.py +++ b/src/sim/status_warehouse/simulate_events/move/load.py @@ -2,9 +2,9 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.move.move import Move -from sim.warehouse import Warehouse, Drawer +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.move.move import Move +from src.sim.warehouse import Warehouse, Drawer logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/move/move.py b/src/sim/status_warehouse/simulate_events/move/move.py index d4dac52..6616419 100644 --- a/src/sim/status_warehouse/simulate_events/move/move.py +++ b/src/sim/status_warehouse/simulate_events/move/move.py @@ -2,9 +2,9 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.action import Action -from sim.warehouse import Warehouse # , Drawer +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.action import Action +from src.sim.warehouse import Warehouse # , Drawer class Move(Action): @@ -24,7 +24,7 @@ def get_destination(self): @abstractmethod def simulate_action(self): - from sim.status_warehouse.simulate_events.move.go_to_deposit import GoToDeposit + from src.sim.status_warehouse.simulate_events.move.go_to_deposit import GoToDeposit # come back to the deposit iff there is a drawer if self.get_warehouse().get_carousel().is_deposit_full(): diff --git a/src/sim/status_warehouse/simulate_events/move/unload.py b/src/sim/status_warehouse/simulate_events/move/unload.py index 9f87c28..99edd27 100644 --- a/src/sim/status_warehouse/simulate_events/move/unload.py +++ b/src/sim/status_warehouse/simulate_events/move/unload.py @@ -2,9 +2,9 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.move.move import Move -from sim.warehouse import Warehouse, Drawer +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.move.move import Move +from src.sim.warehouse import Warehouse, Drawer logger = logging.getLogger(__name__) @@ -15,7 +15,7 @@ def __init__(self, env: Environment, warehouse: Warehouse, simulation: Simulatio super().__init__(env, warehouse, simulation, destination, drawer) def simulate_action(self): - from sim.status_warehouse.enum_warehouse import EnumWarehouse + from src.sim.status_warehouse.enum_warehouse import EnumWarehouse logger.debug(f"Time {self.env.now:5.2f} - Start unloading a drawer") yield self.env.process(self.get_warehouse().unload( self.get_drawer(), diff --git a/src/sim/status_warehouse/simulate_events/move/vertical.py b/src/sim/status_warehouse/simulate_events/move/vertical.py index 78ee418..ab9575f 100644 --- a/src/sim/status_warehouse/simulate_events/move/vertical.py +++ b/src/sim/status_warehouse/simulate_events/move/vertical.py @@ -2,10 +2,10 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.move.move import Move -from sim.warehouse import Warehouse, Drawer -from sim.status_warehouse.enum_warehouse import EnumWarehouse +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.move.move import Move +from src.sim.warehouse import Warehouse, Drawer +from src.sim.status_warehouse.enum_warehouse import EnumWarehouse logger = logging.getLogger(__name__) diff --git a/src/sim/status_warehouse/simulate_events/send_back_drawer.py b/src/sim/status_warehouse/simulate_events/send_back_drawer.py index de00ced..82ffc93 100644 --- a/src/sim/status_warehouse/simulate_events/send_back_drawer.py +++ b/src/sim/status_warehouse/simulate_events/send_back_drawer.py @@ -2,14 +2,14 @@ from simpy import Environment -from sim.simulation import Simulation -from sim.status_warehouse.simulate_events.move.load import Load -from sim.status_warehouse.simulate_events.move.move import Move -from sim.status_warehouse.simulate_events.move.unload import Unload -from sim.status_warehouse.simulate_events.move.vertical import Vertical -from sim.status_warehouse.simulate_events.buffer import Buffer -from sim.warehouse import Warehouse -from sim.status_warehouse.simulate_events.action_enum import ActionEnum +from src.sim.simulation import Simulation +from src.sim.status_warehouse.simulate_events.move.load import Load +from src.sim.status_warehouse.simulate_events.move.move import Move +from src.sim.status_warehouse.simulate_events.move.unload import Unload +from src.sim.status_warehouse.simulate_events.move.vertical import Vertical +from src.sim.status_warehouse.simulate_events.buffer import Buffer +from src.sim.warehouse import Warehouse +from src.sim.status_warehouse.simulate_events.action_enum import ActionEnum class SendBackDrawer(Move): diff --git a/src/sim/utils/save_warehouse_state.py b/src/sim/utils/save_warehouse_state.py index c2b497c..a4551d1 100644 --- a/src/sim/utils/save_warehouse_state.py +++ b/src/sim/utils/save_warehouse_state.py @@ -1,6 +1,6 @@ import os.path -from sim.status_warehouse.entry.drawer_entry import DrawerEntry -from sim.warehouse import Warehouse +from src.sim.status_warehouse.entry.drawer_entry import DrawerEntry +from src.sim.warehouse import Warehouse def save_config(warehouse: Warehouse): @@ -10,10 +10,11 @@ def save_config(warehouse: Warehouse): @param warehouse: warehouse to save. """ # if the directory doesn't exist, create it - if not os.path.isdir("../../tmp"): - os.mkdir("../../tmp") + directory = './tmp' + if not os.path.isdir(directory): + os.mkdir(directory) # create file - with open("../../tmp/config_warehouse.txt", 'w') as file: + with open(f"{directory}/config_warehouse.txt", 'w') as file: # header file.write(f"Warehouse situation\n") file.write("\n") diff --git a/src/sim/utils/statistics/README.md b/src/sim/utils/statistics/README.md index b0b4fd3..599f7f7 100644 --- a/src/sim/utils/statistics/README.md +++ b/src/sim/utils/statistics/README.md @@ -35,7 +35,7 @@ To instantiate the class, all that is required are the items obtained from a Pan This object must be instantiated using the history of the warehouse simulation: ```python from pandas import DataFrame -from sim.utils.statistics.warehouse_statistics import WarehouseStatistics +from src.sim.utils.statistics.warehouse_statistics import WarehouseStatistics from src.sim.warehouse import Warehouse warehouse = Warehouse() diff --git a/src/sim/utils/statistics/warehouse_statistics.py b/src/sim/utils/statistics/warehouse_statistics.py index ad2100a..0fda590 100644 --- a/src/sim/utils/statistics/warehouse_statistics.py +++ b/src/sim/utils/statistics/warehouse_statistics.py @@ -1,6 +1,6 @@ from pandas import DataFrame, Series, Timedelta, Timestamp, Period from enum import Enum -from sim.status_warehouse.simulate_events.action_enum import ActionEnum +from src.sim.status_warehouse.simulate_events.action_enum import ActionEnum class TimeEnum(Enum): diff --git a/src/sim/warehouse.py b/src/sim/warehouse.py index ad3e137..09472a2 100644 --- a/src/sim/warehouse.py +++ b/src/sim/warehouse.py @@ -17,11 +17,11 @@ import copy import random from simpy import Environment -from sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton -from sim.drawer import Drawer -from sim.status_warehouse.container.carousel import Carousel -from sim.status_warehouse.container.column import Column -from sim.status_warehouse.entry.drawer_entry import DrawerEntry +from src.sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton +from src.sim.drawer import Drawer +from src.sim.status_warehouse.container.carousel import Carousel +from src.sim.status_warehouse.container.column import Column +from src.sim.status_warehouse.entry.drawer_entry import DrawerEntry logger = logging.getLogger(__name__) @@ -39,7 +39,7 @@ def gen_materials_and_drawer(num_drawers: int, num_materials: int, :param col: column selected where to put the drawers :return: [number of drawers left, number of materials left] """ - from sim.material import gen_rand_materials + from src.sim.material import gen_rand_materials # generate "rand_num_drawers" drawers for rand_num in range(rand_num_drawers): @@ -110,7 +110,7 @@ def min_search_alg(self, space_req: int) -> list: :param space_req: space requested from drawer. :return: negative values if there isn't any space, otherwise [space_requested, index_position_where_insert]. """ - from sim.status_warehouse.entry.empty_entry import EmptyEntry + from src.sim.status_warehouse.entry.empty_entry import EmptyEntry min_space = self.get_height_warehouse() count = 0 start_index = self.get_height_last_position() @@ -178,7 +178,7 @@ def min_search_alg(self, space_req: int) -> list: class Warehouse: def __init__(self): - from sim.material import gen_rand_material + from src.sim.material import gen_rand_material # open YAML configuration file config: dict = WarehouseConfigurationSingleton.get_instance().get_configuration() @@ -419,7 +419,7 @@ def unload(self, drawer: Drawer, rmv_from_cols: bool): # break def load(self, drawer: Drawer, destination: str): - from sim.status_warehouse.enum_warehouse import EnumWarehouse + from src.sim.status_warehouse.enum_warehouse import EnumWarehouse # take destination coordinates dest_x_drawer = drawer.get_best_offset_x() dest_y_drawer = drawer.get_best_y() @@ -479,7 +479,7 @@ def gen_rand(self, num_drawers: int, num_materials: int): logger.warning(f"The warehouse is full, num_drawers left: {num_drawers}, num_materials left: {num_materials}") def run_simulation(self): - from sim.simulation import Simulation + from src.sim.simulation import Simulation self.env = Environment() self.simulation = Simulation(self.env, self) diff --git a/src/sim/warehouse_configuration_singleton.py b/src/sim/warehouse_configuration_singleton.py index 8f24ec7..5970502 100644 --- a/src/sim/warehouse_configuration_singleton.py +++ b/src/sim/warehouse_configuration_singleton.py @@ -1,4 +1,4 @@ -from sim.configuration import WAREHOUSE_CONFIGURATION +from src.sim.configuration import WAREHOUSE_CONFIGURATION from pathlib import Path from yaml import safe_load from json import loads diff --git a/src/web_app/index.py b/src/web_app/index.py index 338cef8..791f16c 100644 --- a/src/web_app/index.py +++ b/src/web_app/index.py @@ -16,16 +16,16 @@ from pandas import DataFrame from src.sim.warehouse import Warehouse -from web_app.components.timeline import Timeline -from web_app.components.navbar import navbar +from src.web_app.components.timeline import Timeline +from src.web_app.components.navbar import navbar from src.web_app.configuration import HOST, PORT, PROXY -from pages import not_found_404 -from sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton -from web_app.layouts.custom_configuration import create_columns_layout -from sim.utils.statistics.warehouse_statistics import WarehouseStatistics, TimeEnum -from sim.utils.statistics.warehouse_statistics import ActionEnum -from web_app.layouts.simulation_statistics import SimulationInput, create_simulation_statistics_layout -from web_app.utils.callbacks_utilities import FieldsNewSimulationArgs, fields_new_simulation_are_valid +from src.web_app.pages import not_found_404 +from src.sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton +from src.web_app.layouts.custom_configuration import create_columns_layout +from src.sim.utils.statistics.warehouse_statistics import WarehouseStatistics, TimeEnum +from src.sim.utils.statistics.warehouse_statistics import ActionEnum +from src.web_app.layouts.simulation_statistics import SimulationInput, create_simulation_statistics_layout +from src.web_app.utils.callbacks_utilities import FieldsNewSimulationArgs, fields_new_simulation_are_valid """ @@ -50,8 +50,8 @@ cache = Cache("./cache") # create the path if it doesn't exist. # this path will be used by the application to create downloadable graphics -if not os.path.isdir('./images'): - os.mkdir('./images') +if not os.path.isdir('src/web_app/images'): + os.mkdir('src/web_app/images') # Import bootstrap components BS = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" @@ -422,11 +422,11 @@ def download_graph(b_svg, b_pdf, b_csv, b_xlsx): # which button is triggered? match ctx.triggered_id: case "dropdown-btn_csv": - timeline.get_dataframe().to_csv("./images/graph_actions.csv") - return dcc.send_file("./images/graph_actions.csv") + timeline.get_dataframe().to_csv("src/web_app/images/graph_actions.csv") + return dcc.send_file("src/web_app/images/graph_actions.csv") case "dropdown-btn_xlsx": - timeline.get_dataframe().to_excel("./images/graph_actions.xlsx") - return dcc.send_file("./images/graph_actions.xlsx") + timeline.get_dataframe().to_excel("src/web_app/images/graph_actions.xlsx") + return dcc.send_file("src/web_app/images/graph_actions.xlsx") case "dropdown-btn_svg": extension = 'svg' case "dropdown-btn_pdf": @@ -434,12 +434,12 @@ def download_graph(b_svg, b_pdf, b_csv, b_xlsx): case _: raise PreventUpdate # create the file - with open(f"./images/graph_actions.{extension}", "w"): + with open(f"src/web_app/images/graph_actions.{extension}", "w"): pass # take graph to download - timeline.get_figure().write_image(f"./images/graph_actions.{extension}", engine='kaleido', width=1920, height=1080) + timeline.get_figure().write_image(f"src/web_app/images/graph_actions.{extension}", engine='kaleido', width=1920, height=1080) return dcc.send_file( - f"./images/graph_actions.{extension}" + f"src/web_app/images/graph_actions.{extension}" ) @@ -977,7 +977,7 @@ def output_stats_actions_completed_menu_triggered(none, ) def download_output_stats_actions_started(b_data_xlsx, b_data_csv, b_scatter_svg, b_scatter_pdf, action_selected): action: ActionEnum | None = ActionEnum.from_str(action_selected.split(" ")[-1]) - file_path = f"./images/graph_stats-actions_started" if action is None else f"./images/graph_stats-action_{action}_started" + file_path = f"src/web_app/images/graph_stats-actions_started" if action is None else f"src/web_app/images/graph_stats-action_{action}_started" extension = '' data: DataFrame = (warehouse_statistics.actions_started_every(TimeEnum.HOUR) if action is None else warehouse_statistics.action_started_every(action, TimeEnum.HOUR)) @@ -1020,7 +1020,7 @@ def download_output_stats_actions_started(b_data_xlsx, b_data_csv, b_scatter_svg ) def download_output_stats_actions_finished(b_data_xlsx, b_data_csv, b_scatter_svg, b_scatter_pdf, action_selected): action: ActionEnum | None = ActionEnum.from_str(action_selected.split(" ")[-1]) - file_path = f"./images/graph_stats-actions_finished" if action is None else f"./images/graph_stats-action_{action}_finished" + file_path = f"src/web_app/images/graph_stats-actions_finished" if action is None else f"src/web_app/images/graph_stats-action_{action}_finished" extension = '' data: DataFrame = (warehouse_statistics.actions_finished_every(TimeEnum.HOUR) if action is None else warehouse_statistics.action_finished_every(action, TimeEnum.HOUR)) @@ -1063,7 +1063,7 @@ def download_output_stats_actions_finished(b_data_xlsx, b_data_csv, b_scatter_sv ) def download_output_stats_actions_completed(b_data_xlsx, b_data_csv, b_scatter_svg, b_scatter_pdf, action_selected): action: ActionEnum | None = ActionEnum.from_str(action_selected.split(" ")[-1]) - file_path = f"./images/graph_stats-actions_completed" if action is None else f"./images/graph_stats-action_{action}_completed" + file_path = f"src/web_app/images/graph_stats-actions_completed" if action is None else f"src/web_app/images/graph_stats-action_{action}_completed" extension = '' data: DataFrame = (warehouse_statistics.actions_completed_every(TimeEnum.HOUR) if action is None else warehouse_statistics.action_completed_every(action, TimeEnum.HOUR)) @@ -1104,7 +1104,7 @@ def _signal_handler(frame, sig): sys.exit(0) -if __name__ == '__main__': +def run_webpage(): signal(SIGINT, _signal_handler) signal(SIGTERM, _signal_handler) app.run(host=HOST, port=PORT, proxy=PROXY, debug=False) diff --git a/src/web_app/layouts/custom_configuration.py b/src/web_app/layouts/custom_configuration.py index 6020796..bbcaa1e 100644 --- a/src/web_app/layouts/custom_configuration.py +++ b/src/web_app/layouts/custom_configuration.py @@ -1,6 +1,6 @@ import dash_bootstrap_components as dbc from dash import html -from sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton +from src.sim.warehouse_configuration_singleton import WarehouseConfigurationSingleton WAREHOUSE_CONFIG = WarehouseConfigurationSingleton.get_instance().get_configuration() COLUMNS = WAREHOUSE_CONFIG['columns'] diff --git a/src/web_app/layouts/simulation_statistics.py b/src/web_app/layouts/simulation_statistics.py index 780b19b..2e4853e 100644 --- a/src/web_app/layouts/simulation_statistics.py +++ b/src/web_app/layouts/simulation_statistics.py @@ -4,8 +4,8 @@ from dash import html, dcc from pandas import DataFrame -from sim.status_warehouse.simulate_events.action_enum import ActionEnum -from sim.utils.statistics.warehouse_statistics import WarehouseStatistics, TimeEnum +from src.sim.status_warehouse.simulate_events.action_enum import ActionEnum +from src.sim.utils.statistics.warehouse_statistics import WarehouseStatistics, TimeEnum class SimulationInput(NamedTuple): diff --git a/vertimag_measurements.jpg b/vertimag_measurements.jpg deleted file mode 100644 index 4f3070d..0000000 Binary files a/vertimag_measurements.jpg and /dev/null differ diff --git a/vertimag_measurements.pdf b/vertimag_measurements.pdf deleted file mode 100644 index 7bd830b..0000000 Binary files a/vertimag_measurements.pdf and /dev/null differ diff --git a/web-page_template.png b/web-page_template.png deleted file mode 100644 index 0ac2d19..0000000 Binary files a/web-page_template.png and /dev/null differ