Skip to content
Snippets Groups Projects
Commit 374040e6 authored by Hock, Benedikt's avatar Hock, Benedikt
Browse files

Merge remote-tracking branch 'refs/remotes/origin/development' into development

parents 307b14d5 b15e4bf6
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id:9d0d63c1 tags:
%% Cell type:markdown id:c9328cd1 tags:
# FAIRe Qualitäts-KPIs
Name:
Datum:
%% Cell type:code id:c61985be tags:
%% Cell type:markdown id:2ee8746d tags:
## Einführung
FAIRe Qualitäts-KPIs schaffen eine transparente und nachvollziehbare Entscheidungsgrundlage. In dieser Lerneinheit sollen sie die Methodik erlernen, indem sie LEGO-Autos zusammenbauen, deren Qualitäts-KPIs bestimmen und miteinander vergleichen.
### Werkzeug für den Zusammenbau
Der Zusammenbau der Autos erfolgt virtuell. Als Werkzeug steht Ihnen das Modul `classes` zur Verfügung. In diesem sind unterschiedliche Klassen und Methoden implementiert (Objektorientierung). Sie erzeugen jeweils Objekte der Klassen. Ein Objekt ist dabei die virtuelle Abbildung eines realen Bauteiles. Die Eigenschaften des Bauteiles werden über die Eigenschaften des Objektes abgebildet.
### Berechnung der Qualitäts-KPIs
KPIs (Key Performance Indikatoren) sind Kenngrößen des Systems. Sie werden über Berechnungsvorschriften (`calculation_rules`) bestimmt. Diese Berechnungsvorschriften sind von Ihnen als python-Funktionen im Modul `calculation_results` zu implementieren.
### Datenblätter
Für den Zusammenbau stehen Ihnen verschiedene Bauteile in unterschiedlichen Ausführungen zur Verfügung. Sie nutzen die Datenblätter, die als `json-Dateien` zur Verfügung gestellt werden, um Ihre Autos zusammenzubauen.
%% Cell type:markdown id:1c702114 tags:
## Eigene Module und Minimalbeispiel
Für die Ausarbeitung nutzen wir zwei eigene Module (Python-Skripte), die im Ordner `functions` gespeichert sind.
Das Modul `calculation_rules` erweitern Sie während der Ausarbeitung. Um die Änderungen zu nutzen, müssen Sie das Notebook neu starten.
Mit einem Minimalbeispiel wird Ihnen gezeigt, wie sie die Module nutzen.
%% Cell type:code id:b2778dee tags:
``` python
# import modules
from functions import calculation_rules
from functions import classes
# TO DO import further modules if necessary
```
%% Cell type:code id:8d0d8deb tags:
%% Cell type:markdown id:3b69752c tags:
### Modul calculation_results
Sie können die unterschiedlichen Funktionen (Berechnungsvorschriften) aufrufen. Beachten Sie dabei die Übergabe- und Rückgabewerte.
%% Cell type:code id:294c680b tags:
``` python
# test the import
calculation_rules.test_function()
```
%% Output
%% Cell type:markdown id:a2c87a3c tags:
### Modul classes
Wir bauen ein Auto zusammen.
%% Cell type:code id:8db386db tags:
``` python
```
%% Cell type:code id:8f2ae9f4 tags:
``` python
```
%% Cell type:markdown id:de070039 tags:
## Aufgabe: Aufbau eines ersten Fahrzeugs
Bauen Sie ein erstes Fahrzeug aus den gegebenen LEGO-Teilen auf.
Das Fahrzeug muss aus Baugruppen, Bauteilen und Komponenten bestehen. Es muss mindestens vier Räder haben und sich durch den elektrischen Antrieb fortbewegen können.
%% Cell type:markdown id:05a8eb21 tags:
### Beschreibung des Fahrzeuges
Beschreiben Sie kurz und präzise Ihr Fahrzeug.
%% Cell type:code id:ccaf3043 tags:
``` python
# initialize componentens
```
%% Cell type:code id:1ea61422 tags:
``` python
# read out properties from datasheets
```
%% Cell type:code id:36f981df tags:
``` python
# set properties
```
%% Cell type:code id:24400d94 tags:
``` python
# export car and its properties
```
%% Cell type:markdown id:c1fef7f0 tags:
## Aufgabe: Bestimmung der Qualität mittels KPIs
Bestimmen Sie die Qualität Ihres Fahrzeugs mittels KPIs.
Die Qualität des Fahrzeugs ist mit mindestens einem KPI je Qualitätsdimension (Aufwand, Verfügbarkeit, Akzeptanz) zu bestimmen. Enwickeln Sie zunächst sinnvolle KPIs, welche mit den gegebenen Daten umsetzbar sind. Halten Sie die Berechnungsvorschriften im Jupyter Notebook fest. Implementieren Sie deren Berechnung für das Gesamtsystem "Fahrzeug" mittels einzelner Funktionen im Skript `calculation_rules`. Sie können zusätzlich Ihre Methoden auch auf die niedrigeren Aggregationsebenen anwenden.
%% Cell type:markdown id:d5f02096 tags:
### Beschreibung KPI
Beschreiben Sie den jeweiligen KPI und geben Sie seine Berechnungsvorschrift an.
$$
a = \frac{b}{c} + d
$$
%% Cell type:code id:59eabafc tags:
``` python
# calculate the KPIs for your car
```
%% Cell type:code id:c774b381 tags:
``` python
# print your KPIs
```
%% Cell type:markdown id:89c75440 tags:
## Aufgabe: Aufbau eines zweiten Fahrzeugs
Setzen Sie sich ein Ziel, welche Qualitätsdimensionen in einem zweiten Fahrzeug verbessert werden sollen und bauen Sie dementsprechend ein zweites Fahrzeug aus den gegebenen LEGO-Teilen auf.
Das Fahrzeug muss aus Baugruppen, Bauteilen und Komponenten bestehen. Es muss mindestens vier Räder haben und sich durch den elektrischen Antrieb fortbewegen können. Die Verwendung eines Getriebes zwischen Motor und Antriebsachse(n) ist verpflichtend. Es sind nur die gegebenen LEGO-Teile zu verwenden.
%% Cell type:markdown id:3cef0828 tags:
### Beschreibung
Beschreiben Sie, welche Verbesserung Sie vornehmen.
...
%% Cell type:markdown id:73c454f2 tags:
### Aufbau des zweiten Fahrzeuges
Beschreiben Sie kurz und präzise den Aufbau des zweiten Fahrzeugs
%% Cell type:code id:ea18e735 tags:
``` python
# build a second car
```
%% Cell type:code id:b3438fc4 tags:
``` python
# read out properties from datasheets
```
%% Cell type:code id:0b7336fb tags:
``` python
# set properties
```
%% Cell type:code id:446abbca tags:
``` python
# export car and its properties
```
%% Cell type:markdown id:89e54480 tags:
### KPIs des zweiten Fahrzeuges
Bestimmen Sie die KPIs des zweiten Fahrzeuges
%% Cell type:code id:762a1e93 tags:
``` python
# calculate the KPIs for your car
```
%% Cell type:code id:1ed67328 tags:
``` python
# print your KPIs
```
%% Cell type:markdown id:e413cd84 tags:
## Aufgabe: Darstellung und Vergleich der Ergebnisse
Stellen Sie die Ergebnisse für beide Fahrzeuge übersichtlich dar.
Die entwickelten KPIs müssen dargestellt und die Datengrundlage ersichtlich sein.
Eine geeignete grafische Darstellung für die Gegenüberstellung der Ergebnisse für beide Fahrzeuge ist zu wählen.
%% Cell type:code id:b0f93e22 tags:
``` python
# plot the data, save diagramm as svg-file
```
%% Cell type:markdown id:62ff04b2 tags:
### Interpretation der Ergebnisse
Interpretieren Sie ihre Ergebnisse. Vergleichen Sie die KPIs ihrer Autos. Konnten Sie ihre gewünschte Verbesserung erzielen?
%% Cell type:markdown id:a0840fbf tags:
You called the test function.
## Aufgabe: Exportieren Sie ihre Daten
Exportieren/ Speichern Sie alle relevaten Daten ab.
%% Cell type:code id:d211b05d tags:
%% Cell type:code id:a4bdfc7a tags:
``` python
# export all relevant data
```
......
......@@ -5,6 +5,8 @@ from collections import namedtuple
from typing import Dict, List, NamedTuple
import pandas as pd
# pandas is using another dependency called openpyxl
# both need to be installed
COLUMN_FOR_INDEX_IN_EXCEL = 0
......@@ -14,8 +16,8 @@ HELP_TXT = """
1. The source excel file. (e.g. test.xlsx)
2. The destination folder for the json file. (e.g. test_folder)
3. Override the folder if existing. (OPTIONAL, False)
Providing only '-- help' will show this text and exit.
Providing only '-- help' will show this text and exit.
"""
......
{
"Pumps":[
{"Name": "Pump_1",
"Manufacturer": "Company A",
"Unit": "Percentage",
"Efficiency": 43},
{"Name": "Pump_2",
"Manufacturer": "Company B",
"Unit": "Percentage",
"Efficiency": 56
}
]
}
'''
"""
File consists of several functions for the calculation rules of FAIR Quality KPIs
'''
"""
def test_function():
print("You called the test function.")
def kpi_sum(*args):
return sum(args[0])
# if arguments are handed over not as a list: sum(list(args))
if __name__ == "__main__":
print("This script contains functions for calculating the FAIR Quality KPIs. It is not to be executed independently.")
pass
\ No newline at end of file
print(
"This script contains functions for calculating the FAIR Quality KPIs. It is not to be executed independently."
)
pass
'''
"""
File consists of several classes for the different elements of a device.
'''
"""
from __future__ import annotations
from enum import Enum, auto
import uuid
from typing import Any, Union, Literal, TypedDict, TypeVar, Type, List, Optional, Dict
from typing import List, Dict
import json
......@@ -15,7 +14,8 @@ import json
# - Gute String Darstellung
# - Minimalbeispiel für KPIs
# - Export als GraphViz
# - Erlaube Listen bei add_component und add_assembly ?
# - Zukunft: Erlaube Clone bei Assembly (jede Component muss durch Klon ersetzt werden)
class ComponentCategory(Enum):
BATTERY = auto()
......@@ -34,8 +34,17 @@ class AggregationLayer(Enum):
class LegoComponent:
def __init__(self, name: str, category: ComponentCategory, lego_id: str, cost: float, mass: float,
delivery_time: int, layer: AggregationLayer = AggregationLayer.COMPONENT, **properties) -> None:
def __init__(
self,
name: str,
category: ComponentCategory,
lego_id: str,
cost: float,
mass: float,
delivery_time: int,
layer: AggregationLayer = AggregationLayer.COMPONENT,
**properties,
) -> None:
self.uuid: uuid.UUID = uuid.uuid4()
self.parent: None | LegoAssembly = None
self.name: str = name
......@@ -48,8 +57,16 @@ class LegoComponent:
self.properties: dict = properties
def clone(self) -> LegoComponent:
clone = LegoComponent(self.name, self.category, self.lego_id, self.cost, self.mass, self.delivery_time,
self.layer, **self.properties)
clone = LegoComponent(
self.name,
self.category,
self.lego_id,
self.cost,
self.mass,
self.delivery_time,
self.layer,
**self.properties,
)
return clone
def get_root_assembly(self):
......@@ -61,7 +78,17 @@ class LegoComponent:
return current_assembly
def to_dict(self) -> Dict:
ATTRIBUTES = ["uuid", "name", "category", "lego_id", "cost", "mass", "delivery_time", "layer", "properties"]
ATTRIBUTES = [
"uuid",
"name",
"category",
"lego_id",
"cost",
"mass",
"delivery_time",
"layer",
"properties",
]
dict_ = {}
# store attributes
for attr in ATTRIBUTES:
......@@ -96,26 +123,34 @@ class LegoAssembly:
def add_component(self, component: LegoComponent) -> None:
if not isinstance(component, LegoComponent):
raise TypeError(f"Argument should be of type {LegoComponent.__name__}, "
f"got {type(component).__name__} instead.")
raise TypeError(
f"Argument should be of type {LegoComponent.__name__}, "
f"got {type(component).__name__} instead."
)
if self.get_root_assembly().contains_uuid(component.uuid):
raise AssertionError(f"This assembly or a subassembly already contains the component with ID "
f"{component.uuid}.")
raise AssertionError(
f"This assembly or a subassembly already contains the component with ID "
f"{component.uuid}."
)
component.parent = self
self.components.append(component)
def add_assembly(self, assembly: LegoAssembly) -> None:
if not isinstance(assembly, LegoAssembly):
raise TypeError(f"Argument should be of type {LegoAssembly.__name__}, "
f"got {type(assembly).__name__} instead.")
raise TypeError(
f"Argument should be of type {LegoAssembly.__name__}, "
f"got {type(assembly).__name__} instead."
)
if self.get_root_assembly().contains_uuid(assembly.uuid):
raise AssertionError(f"This assembly or a subassembly already contains the assembly with ID "
f"{assembly.uuid}.")
raise AssertionError(
f"This assembly or a subassembly already contains the assembly with ID "
f"{assembly.uuid}."
)
assembly.parent = self
self.assemblies.append(assembly)
def children(self) -> Dict[str, List[LegoComponent] | List[LegoAssembly]]:
return {'components': self.components, 'assemblies': self.assemblies}
return {"components": self.components, "assemblies": self.assemblies}
def get_component_list(self, max_depth: int = -1) -> List[LegoComponent]:
component_list = []
......
'''
"""
FAIR Quality KPIs
'''
"""
def main ():
def main():
print("Hello ;-)")
pass
if __name__ == "__main__":
main()
\ No newline at end of file
main()
%% Cell type:code id: tags:
``` python
# import functions.lego_classes as lego_classes
from functions.lego_classes import LegoItem
from functions.lego_classes import LegoComponent
from functions.classes import LegoItem
from functions.classes import LegoComponent
```
%% Cell type:code id: tags:
``` python
# Test manually creating some item and components
item1 = LegoItem(1,0.10,10)
item2 = LegoItem(3,0.30,30)
item3 = LegoItem(2, 0.2,20)
component1 = LegoComponent()
# component1.add_item(item1)
component2 = LegoComponent(item2)
componentall = LegoComponent([component1,component2]) # This will be saved as items for some reasaon
# component3 = LegoComponent(item3,component1)
# component3.add(item2) # Can't really use an item twice
# component3.add(component2)
print(componentall.items)
```
%% Output
[<functions.lego_classes.LegoComponent object at 0x000002720F4BF7F0>, <functions.lego_classes.LegoComponent object at 0x000002720F4BF790>]
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
## Let's test the json stuff
import json
# import tkinter as tk
```
%% Cell type:code id: tags:
``` python
# First level list handling
def read_json(file_path):
with open(file_path, 'r') as f:
data = json.load(f)
return data
json_list_data = read_json('example_item_data_list.json')
# that produces a list, we'd prefer a dict
# Clever way to just create an item for each listed element
def create_all_items(data):
items = []
for item_data in data:
item_number = item_data.get('item_number')
mass = item_data.get('mass')
delivery_time = item_data.get('delivery_time')
# specific_data = item_data.get('specific_data', {})
item = LegoItem(item_number, mass, delivery_time)
items.append(item)
return items
all_items = create_all_items(json_list_data)
# How to get entries for a specific item
def get_item_by_number(data, item_number):
datasheet = [item for item in data if item['item_number' ] == item_number]
return datasheet
sheet1 = get_item_by_number(json_list_data, 2) # this is a list? meh
```
%% Cell type:code id: tags:
``` python
# vs first level dict handling
with open('example_item_data_dict.json') as json_file:
json_dict = json.load(json_file)
print(type(json_dict))
print(json_dict["1"])
sheet2_from_dict = json_dict["2"]
# Create an item for this:
def create_item_from_sheet(dict):
item_number = dict["item_number"]
mass = dict["mass"]
delivery_time =["delivery_time"]
item = LegoItem(item_number, mass, delivery_time)
return item
itemfromdict = create_item_from_sheet(sheet2_from_dict)
```
%% Output
<class 'dict'>
{'item_number': 1, 'mass': 10, 'delivery_time': 1}
......
# import standard libraries
import json
import pprint
# import classes from the classes module in functions package
from functions.classes import LegoComponent
from functions.classes import LegoAssembly
from functions.classes import ComponentCategory
from functions.classes import AggregationLayer
from functions.classes import KPIEncoder
from functions.classes import print_assembly_tree
from functions.calculation_rules import kpi_sum
# Test manually creating some assemblies and components
battery = LegoComponent("nice battery", ComponentCategory.BATTERY, "bat42", 1, 2, 3)
motor = LegoComponent("motor goes brrr", ComponentCategory.MOTOR, "motor", 1, 2, 3)
wheel = LegoComponent("much round wheel", ComponentCategory.WHEEL, "round", 1, 2, 3)
# Create subassemblies and combine to assembly (currently no parts present for this)
chassis = LegoAssembly("Chassis", AggregationLayer.ASSEMBLY)
door1 = LegoAssembly("Door 1", AggregationLayer.SUBASSEMBLY)
door2 = LegoAssembly("Door 2", AggregationLayer.SUBASSEMBLY)
chassis.add_assembly(door1)
chassis.add_assembly(door2)
chassis.properties
engine = LegoAssembly("Engine", AggregationLayer.ASSEMBLY)
# Showcase cloning - one motor for each axis?
engine.add_component(motor.clone())
fuel_tank = LegoAssembly("Fuel Tank", AggregationLayer.ASSEMBLY)
fuel_tank.add_component(battery.clone())
wheels = LegoAssembly("Wheels", AggregationLayer.ASSEMBLY)
for _ in range(4):
wheels.add_component(wheel.clone())
# Create and assemble the system level car
car = LegoAssembly("Car", AggregationLayer.SYSTEM)
car.add_assembly(chassis)
car.add_assembly(engine)
car.add_assembly(fuel_tank)
car.add_assembly(wheels)
## Printing
print_assembly_tree(car)
# Dump to json file
with open("car.json", "w") as fp:
json.dump(car.to_dict(), fp, cls=KPIEncoder)
pprint.pprint(car.to_dict())
pass
## Create components from datasheet
# Need to run the script from datasheets folder first
# Test loading dicts from datasheet jsons
with open('datasheets/Achsen.json') as json_file:
Achsen = json.load(json_file)
print((Achsen["Achse 5 studs"]))
# This is hard to read, prettier please!
pprint.pprint(Achsen)
# Okay I'll use the 5 stud one
Achse5 = Achsen["Achse 5 studs"] # I'd prefer to call it via "Designnummer"
print(Achsen["Achse 5 studs"]["Designnummer"])
with open('datasheets/Räder.json') as json_file:
Raeder = json.load(json_file)
# Get me the expensive one
Radpreis = []
for key in Raeder: # a list would work easier here than a dict
Radpreis.append(Raeder[key]["Preis [Euro]"])
Radpreis = max(Radpreis)
for key in Raeder:
if Raeder[key]["Preis [Euro]"] == Radpreis:
TeuresRad=Raeder[key]
# Also need a frame
with open('datasheets/Gestell.json') as json_file:
Gestelle = json.load(json_file)
Gestellbeschreibung = "Technic, Brick 1 x 8 with Holes"
Gestell = Gestelle[Gestellbeschreibung]
# Create Components from these items
# LegoComponent(name: str, category: ComponentCategory, lego_id: str, cost: float,
# mass: float, delivery_time: int, layer: AggregationLayer = AggregationLayer.COMPONENT, **properties)
scooterframe = LegoComponent("running board", ComponentCategory.FRAME,
Gestell["Designnummer"],
Gestell["Preis [Euro]"], Gestell["Gewicht [g]"],
0)
scooterwheel = LegoComponent("Vorderrad", ComponentCategory.WHEEL,
TeuresRad["Designnummer"],
TeuresRad["Preis [Euro]"], TeuresRad["Gewicht [g]"],
0)
# Cloning is necessary because each lego object gets a unique id so you can't use the same part twice
scooterwheel2 = scooterwheel.clone()
scooterwheel2.name = "Hinterrad"
print([scooterwheel.uuid, scooterwheel2.uuid])
# Lets Assembly, first the Assembly object, directly add the frame?
scooter = LegoAssembly("my first scooter", AggregationLayer.SYSTEM)
scooter.add_component(scooterframe) # only one per call for now
scooter.add_component(scooterwheel)
scooter.add_component(scooterwheel2)
# <Assembly>.add_assembly() works in the same way
# Look at our work:
print(scooter)
print(scooter.children())
## First KPI mass should be a sum
listofmasses= []
for c in scooter.components:
listofmasses.append(c.mass)
for a in scooter.assemblies:
# only checking one layer deep here
listofmasses.append(a.mass)
print(listofmasses)
print(kpi_sum(listofmasses))
print("theend")
\ No newline at end of file
# import functions.lego_classes as lego_classes
from functions.lego_classes import *
import json
import pprint
# Test manually creating some item and components
battery = LegoComponent("nice battery", ComponentCategory.BATTERY, "bat42", 1, 2, 3)
motor = LegoComponent("motor goes brrr", ComponentCategory.MOTOR, "motor", 1, 2, 3)
wheel = LegoComponent("much round wheel", ComponentCategory.WHEEL, "round", 1, 2, 3)
car = LegoAssembly("Car", AggregationLayer.SYSTEM)
chassis = LegoAssembly("Chassis", AggregationLayer.ASSEMBLY)
door1 = LegoAssembly("Door 1", AggregationLayer.SUBASSEMBLY)
door2 = LegoAssembly("Door 2", AggregationLayer.SUBASSEMBLY)
chassis.add_assembly(door1)
chassis.add_assembly(door2)
engine = LegoAssembly("Engine", AggregationLayer.ASSEMBLY)
engine.add_component(motor.clone())
fuel_tank = LegoAssembly("Fuel Tank", AggregationLayer.ASSEMBLY)
fuel_tank.add_component(battery.clone())
wheels = LegoAssembly("Wheels", AggregationLayer.ASSEMBLY)
for _ in range(4):
wheels.add_component(wheel.clone())
car.add_assembly(chassis)
car.add_assembly(engine)
car.add_assembly(fuel_tank)
car.add_assembly(wheels)
print_assembly_tree(car)
# Dump to json file
with open("car.json", "w") as fp:
json.dump(car.to_dict(), fp, cls=KPIEncoder)
pprint.pprint(car.to_dict())
pass
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment