Skip to content

Latest commit

 

History

History
322 lines (242 loc) · 7.32 KB

structure.md

File metadata and controls

322 lines (242 loc) · 7.32 KB

multi-project Research Operationnel platform

✔ one shared main interface ✔ multiple project modules (MCLP, Transport, Scheduling, etc.) ✔ each project isolated in its own folder ✔ a clean separation between GUI and logic ✔ a future NestJS API integration layer


✅ 1. Final Unified Project Structure (RO-Project)

RO-Project/
│
├── main.py
│
├── interface/                      # Global GUI
│   ├── main_window.py              # Home screen with project selection
│   ├── base_project_window.py      # Abstract class for all project interfaces
│   ├── wifi_mclp_window.py         # Your Wi-Fi GUI
│   ├── transport_window.py         # Example project 2
│   ├── scheduling_window.py        # Example project 3
│   ├── graphs_window.py            # Example project 4
│   ├── facility_location_window.py # Example project 5
│   └── resources/                  # Icons, style, .ui files
│
├── projects/                       # Each project’s logic lives here
│   ├── wifi_mclp/                  # Your project
│   │   ├── data/
│   │   │   ├── data_loader.py
│   │   │   └── preprocessing.py
│   │   ├── models/
│   │   │   ├── mclp_model.py
│   │   │   └── constraints.py
│   │   ├── solver/
│   │   │   └── gurobi_solver.py
│   │   ├── services/
│   │   │   └── wifi_service.py      # Core function exposed for API or UI
│   │   └── utils/
│   │       ├── geometry.py
│   │       ├── map_visualizer.py
│   │       └── logger.py
│   │
│   ├── transport/                  # Project 2 (Transport Problem)
│   │   ├── models/…
│   │   ├── solver/…
│   │   ├── services/transport_service.py
│   │   └── data/...
│   │
│   ├── scheduling/                 # Project 3 (Shift Scheduling)
│   │   ├── models/…
│   │   ├── solver/…
│   │   ├── services/scheduling_service.py
│   │   └── data/...
│   │
│   ├── graphs/                     # Project 4 (Graph Coloring)
│   │   ├── models/…
│   │   ├── solver/…
│   │   ├── services/graph_service.py
│   │   └── data/...
│   │
│   └── facility_location/          # Project 5 (Location-Allocation for example)
│       ├── models/…
│       ├── solver/…
│       ├── services/facility_service.py
│       └── data/...
│
├── api/                            # For NestJS to call Python
│   ├── run_service.py              # ONE entry point for ALL projects
│   └── dispatch.py                 # Routes API calls to correct service
│
├── tests/
│   ├── test_wifi.py
│   ├── test_transport.py
│   ├── test_scheduling.py
│   └── ...
│
├── requirements.txt
└── README.md

🧩 Explanation of each component

Below is a simple but professional-level description.


1️⃣ main.py

Starts the app:

from interface.main_window import MainWindow
from PyQt5.QtWidgets import QApplication
import sys

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

Nothing more. No business logic. No data. No models.


2️⃣ interface/main_window.py

This is the homepage, showing buttons:

  • Wi-Fi MCLP
  • Transport
  • Scheduling
  • Graph Coloring
  • Facility Location

Each button opens the corresponding project window:

# Example
def open_wifi_project(self):
    from interface.wifi_mclp_window import WifiMCLPWindow
    self.child = WifiMCLPWindow()
    self.child.show()

This ensures isolation between projects.


3️⃣ interface/wifi_mclp_window.py

Your GUI:

  • fields: radius, number of repeaters, capacity, etc.
  • load data buttons
  • run optimization button
  • show map / results

When the user clicks "Run":

from projects.wifi_mclp.services.wifi_service import run_mclp

params = {
    "radius": self.radius_input.value(),
    "max_repeaters": self.k_input.value(),
    "capacity": self.cap_input.value()
}

result = run_mclp(params)
self.display_results(result)

GUI only talks to services, never to models.


4️⃣ projects/wifi_mclp/services/wifi_service.py

This is the heart of your system.

It is used by:

✔ PyQt GUI ✔ NestJS API ✔ Unit tests ✔ Command-line test

Example:

def run_mclp(params):
    # 1. Load data
    points = data_loader.load_points()
    
    # 2. Preprocess
    coverage_matrix = preprocessing.compute_coverage_matrix(points, params["radius"])

    # 3. Build model
    model = mclp_model.build_model(coverage_matrix, params)

    # 4. Solve
    solution = gurobi_solver.solve(model)

    # 5. Format result
    return {
        "selected_sites": solution.sites,
        "coverage_percentage": solution.coverage,
        "objective": solution.obj_value
    }

This function returns a clean dictionary → perfect for JSON.


5️⃣ projects/wifi_mclp/models/mclp_model.py

Builds the mathematical program:

def build_model(coverage_matrix, params):
    m = gp.Model("MCLP")
    
    # variables
    x = m.addVars(num_sites, vtype=GRB.BINARY)
    y = m.addVars(num_points, vtype=GRB.BINARY)

    # coverage constraint
    for i in points:
        m.addConstr(y[i] <= gp.quicksum(x[j] for j in sites if coverage[i][j] == 1))

    # limit on repeater count
    m.addConstr(x.sum() <= params["max_repeaters"])

    # objective
    m.setObjective(gp.quicksum(demand[i] * y[i] for i in points), GRB.MAXIMIZE)

    return m

This is pure OR science, no GUI.


6️⃣ api/run_service.py

This is what NestJS will call.

Example:

python api/run_service.py --project wifi_mclp --radius 200 --max_repeaters 6

The script does:

from api.dispatch import dispatch_request

params = parse_args()
output = dispatch_request(params)
print(json.dumps(output))

7️⃣ api/dispatch.py

Routes API calls:

from projects.wifi_mclp.services.wifi_service import run_mclp
from projects.transport.services.transport_service import run_transport
...

def dispatch_request(params):
    project = params["project"]

    if project == "wifi_mclp":
        return run_mclp(params)

    elif project == "transport":
        return run_transport(params)
    
    # etc.

    else:
        raise Exception("Unknown project")

🌐 How NestJS will call Python

NestJS will execute:

const result = await execa('python', [
  'api/run_service.py',
  '--project', 'wifi_mclp',
  '--radius', '150',
  '--max_repeaters', '5'
]);

You receive stdout, parse JSON:

return JSON.parse(result.stdout);

The Python service returns:

{
  "selected_sites": [3, 7, 9],
  "coverage_percentage": 88.5,
  "objective": 1450,
  "map_path": "output/map.png"
}

This is clean and maintainable.


🎯 What this architecture gives you

✔ 5 people can work independently. ✔ Every project is isolated (clean code boundaries). ✔ GUI is separate from logic. ✔ Python services reusable by NestJS API. ✔ Easy unit testing. ✔ Code stays readable and professional.