Seite 1 von 2

Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 12:24
von Dennis89
Hallo zusammen,

ich bin mir wieder gar nicht sicher, wie ich meinen Code aufbauen sollen. Es geht wieder um ein Berechnungsprogramm und man kann es vielleicht mit einen Motor wieder ganz gut erklären.
Sagen wir ich will Motoren berechnen, die haben entweder einen Zylinder, zwei Zylinder oder drei. Die werden alle über die gleiche Kurbelwelle angetrieben, können aber unterschiedliche Kolbendurchmesser haben. Verschiedene Kenngrößen des gesamten Motors hängen davon ab wie viele Zylinder der Motor hat und auch ob die Kolbendurchmesser gleich oder unterschiedlich sind.

Ich sehe das so: Egal welche Konfiguration ich habe, ich habe einen Basismotorblock, der hat Attribute wie Drehzahl, Hub, etc. die unabhängig von der Anzahl der Zylinder sind. Dann würde ich eine Klasse "Motorblock" schreiben und eine weitere Klasse "Zylinder" die von "Motorblock" erbt und je nach Anzahl von Zylinder würde ich in meinem Programm dann entsprechend viele Instanzen "Zylinder" erstellen.

Das wäre dann beispielhaft so etwas:

Code: Alles auswählen

#!/usr/bin/env python
from attr import define, field
from math import pi


@define
class MotorBlock:
    speed = field()
    stroke = field()

    @property
    def mean_piston_speed(self):
        return 2 * self.stroke * 2 * self.speed


@define
class Cylinder(MotorBlock):
    piston_diameter = field()

    @property
    def piston_area(self):
        return pi * self.piston_diameter**2 / 4


def main():
    input_data = {"speed": 500, "stroke": 120, "pistons": [100, 60]}
    cylinders = [
        Cylinder(input_data["speed"], input_data["stroke"], piston_diameter)
        for piston_diameter in input_data["pistons"]
    ]
   


if __name__ == "__main__":
    main()
Oder ich könnte anstatt die "Zylinder" Klasse mehrere Klassen machen, eine "Einzylinder", eine "Zweizylinder" und eine "Dreizylinder" und die erben von "Motorblock", oder ich betrachte alles als "Motor" und die Attribute Kolbendurchmesser werden Listen, dann kann ich immer durch die Liste iterieren und/oder anhand der Länge der Liste dann berechnen und erkennen wie viele Zylinder der Motor hat.

Ich denke alle drei Möglichkeiten funktionieren, nur wenn ich immer eure Code-Beispiele sehe, sieht man da eine klare Struktur und die sind gut erweiterbar. Welche Struktur würdet ihr wählen?
Berechnet werden Kennzahlen die nur die einzelnen Zylinder betreffen, aber auch den gesamten Motor wo die Anzahl und das Zusammenspiel der Zylinder mit einspielt.


Danke und Grüße
Dennis

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 12:30
von __blackjack__
@Dennis89: Der Beispielcode sieht falsch aus, denn Vererbung beschreibt ja eine „ist-ein(e)“-Beziehung und ein Zylinder ist kein Motorblock. Ein Motor(block) *hat* Zylinder, also Komposition.

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 12:36
von narpfel
Allgemeine Faustregel:
Code-Strukturierung, macht Vererbung hier Sinn?
Nein.
Dennis89 hat geschrieben: Sonntag 27. Oktober 2024, 12:24 Sagen wir ich will Motoren berechnen, die haben entweder einen Zylinder, zwei Zylinder oder drei.
Dann sollte ein `Motor` eine Liste von Zylindern haben. Oder, wenn alle Zylinder gleich sind: Eine Anzahl von Zylindern. Also ein Attribut `cylinder_count`.

Code: Alles auswählen

@define
class Cylinder(MotorBlock):
    ...
Das sagt aus, dass ein Zylinder ein Motorblock ist. Also genau das Gegenteil von dem, was du vorher im Text beschrieben hast.
Oder ich könnte anstatt die "Zylinder" Klasse mehrere Klassen machen, eine "Einzylinder", eine "Zweizylinder" und eine "Dreizylinder" und die erben von "Motorblock"
Wenn es Unterschiede zwischen Ein-, Zwei- und Dreizylindermotoren gibt... Vielleicht. Aber das sieht eher so aus, als wenn du die Anzahl der Zylinder im Klassennamen kodieren willst, obwohl das eigentlich ein Wert sein sollte.
oder ich betrachte alles als "Motor" und die Attribute Kolbendurchmesser werden Listen, dann kann ich immer durch die Liste iterieren und/oder anhand der Länge der Liste dann berechnen und erkennen wie viele Zylinder der Motor hat.
Das würde ich im Kontext von diesem Beispiel nicht machen, weil du damit zusammenhängende Daten in verschiedene Listen aufteilst. Aber bei deinem eigentlichen Problem kann das auch die Lösung sein.

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 17:10
von Dennis89
Danke für eure Antworten.

Okay das sehe ich.
Aber das sieht eher so aus, als wenn du die Anzahl der Zylinder im Klassennamen kodieren willst, obwohl das eigentlich ein Wert sein sollte.
Ja der Gedanke steckte dahinter, dass ich die Klassen so nennen wollte.

Hm wenn ich das richtig raus lesen, dann wäre die Klasse "Motor" mit Listen als Attribute wohl der Weg den ich am ehesten gehen soll. Oder habt ihr noch eine Alternative?


Grüße
Dennis

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 17:21
von narpfel
Dennis89 hat geschrieben: Sonntag 27. Oktober 2024, 17:10 dann wäre die Klasse "Motor" mit Listen als Attribute wohl der Weg den ich am ehesten gehen soll.
Was sollen diese Listen enthalten?

=>
narpfel hat geschrieben: Sonntag 27. Oktober 2024, 12:36
oder ich betrachte alles als "Motor" und die Attribute Kolbendurchmesser werden Listen, dann kann ich immer durch die Liste iterieren und/oder anhand der Länge der Liste dann berechnen und erkennen wie viele Zylinder der Motor hat.
Das würde ich im Kontext von diesem Beispiel nicht machen, weil du damit zusammenhängende Daten in verschiedene Listen aufteilst. Aber bei deinem eigentlichen Problem kann das auch die Lösung sein.

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 17:31
von Sirius3
@Dennis89:ja, nach Deinem Beispiel hätte ein Motor eine Liste mit Zylindern.

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 18:15
von Dennis89
Also eigentlich habe ich eine Liste mit unterschiedlichen Kolbendurchmesser und dann hat jeder Zylinder noch 4 Faktoren, also noch mal viert Attribute mit Listen die zu den Zylindern die entsprechenden Faktoren enthalten. Die Faktoren dienen dazu um die Berechnung an die Realität an zu nähern und basieren auf Versuche.

Was mir gerade noch einfällt, der Benutzer wählt einen Motor aus und je nach Typ sind dann die unterschiedlichen Zylinder mit Faktoren in einer Datenbank (die noch nicht existiert) vorhanden. Vielleicht erinnert ihr euch noch an die Kühlerberechnung von mir, das hier soll so ähnlich werden und ganz in der Zukunft wird dann alles vereint.

Um auf mein kleines Beispiel von oben zurück zu kommen, `speed` ist eine Benutzereingabe und je nach dem welchen Motortyp er ausgewählt hat, kommen die anderen Daten aus der Datenbank. Falls diese Info für die Klasse wichtig wäre.

Oder kann das sein, dass das alles noch recht abstrakt ist und ich einfach mal loslegen soll und euch den Code zeigen, wenn er mal ein paar Sachen macht um was sinnvolles zu sagen?

Danke und Grüße
Dennis

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Sonntag 27. Oktober 2024, 20:30
von Dennis89
Oh man, die Berechnungen werden so zum absoluten Chaos, was ich da dann an Listen hin und her reichen muss, da blickt kein Mensch mehr durch.

Das Problem ist, das ein Teil der Berechnung so lange die Drücke der einzelnen Zylinder anpasst, bis sich im Gasstrom ein Gleichgewicht einstellt. Weil die aber unterschiedliche Durchmesser haben, sind auch die Drücke unterschiedlich. Da wäre es geschickt wenn ich den Gasstrom pro Zylinder berechnen könnte und danach alle Ergebnisse vergleiche. Aber das bedeutet hier auch noch viele Index-Zugriffe auf Listen. Das will ich vermeiden. Bin mit aktuell nicht sicher, ob ich die Rechnungen hier so frei ins Netz stellen darf.

Jeden Zylinder als einzelnen Motor zu betrachten wäre irgendwie auch nicht ganz richtig, aber die Rechnungen wäre verständlicher und vielleicht könnte man die einzelnen Zylinder nachher zu einem Motor "zusammen setzen". Die Idee kam mir, wenn ich an Schiffsmotoren denke, die können einzelne Zylinder ausschalten, das ist ja dann eigentlich ein Motorabschnitt der eine einzelne Klasse sein könnte. Wenn ich dann zum Beispiel diee Abtriebsleistung berechnen will, dann "baue" ich aus den einzlnen Motorabschnitten einen Motor(-klasse) ? Oder ist das zu kreativ?

Danke und Grüße
Dennis

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 00:15
von grubenfox
Dennis89 hat geschrieben: Sonntag 27. Oktober 2024, 18:15 Oder kann das sein, dass das alles noch recht abstrakt ist und ich einfach mal loslegen soll und euch den Code zeigen, wenn er mal ein paar Sachen macht um was sinnvolles zu sagen?
Für mich wären erst mal Daten(-strukturen) viel interessanter als irgendein Code...
Dennis89 hat geschrieben: Sonntag 27. Oktober 2024, 18:15 Also eigentlich habe ich eine Liste mit unterschiedlichen Kolbendurchmesser und dann hat jeder Zylinder noch 4 Faktoren, also noch mal viert Attribute mit Listen die zu den Zylindern die entsprechenden Faktoren enthalten. Die Faktoren dienen dazu um die Berechnung an die Realität an zu nähern und basieren auf Versuche.
also ein Zylinder hat einen Kolbendurchmesser und 4 weitere Faktoren. Die kann man auch Attribute nennen... (da bin ich noch dabei) Aber wieso jetzt wieder irgendwelche Listen? Ich stelle mich mal dumm [fällt mir aufgrund großer Ahnungslosigkeit gerade sehr leicht ;) ] und stell mal die Behauptung in den Raum dass ein Zylinder gar keine Listen hat. Er hat halt einige Attribute (darunter den Kolbendurchmesser) und das war's.

Dann gibt's da offenbar noch eine Python-Funktion (falls der Zylinder mal eine Python-Klasse wird, wird aus der Funktion dann vielleicht eine Methode dieser Klasse) die irgendwie mit einem Zylinder, einem Druck und dem Gasstrom herum hantiert. Hier ist mir nicht klar in wie weit Druck und Gasstrom nun Ausgaben und/oder Eingabeparameter der Funktion sind. Die Daten, die einen Zylinder beschreiben, gehen wohl nur in die Funktion rein...

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 06:25
von Dennis89
Danke für die Antwort.

Welche Datenstruktur meinst du denn?

Ein Zylinder hat keine Listen, die Idee war ja, dass die Motor-Klasse ein Attribut "Kolbendurchmesser" hat und dass ist dann eine Liste mit mehreren Durchmessern und anhand von denen kann man auf die Zylinderanzahl schließen.

Druck sind Eingabeparameter und der Gasstrom ist das Ergebnis der Berechnung.


Grüße
Dennis

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 07:01
von sparrow
@Dennis89: Ich glaube, du bist hier gedanklich viel zu sehr in irgendwelchen Datenstrukturen gefangen. Eigentlich sollte es so sein, dass sich die Struktur aus der Realität ergibt.

Vorweg: Dass die Vererbung keinen Sinn macht, wurde gesagt und ist wurde auch verstanden?

Ein Problem ist natürlich, dass niemand außer dir weiß, was da am Ende passieren soll. Deshalb ist das ein bisschen Fischen im Trüben und man kann nur sehr oberflächliche Aussagen treffen. Bis zu deinem letzten Post, ist das, was dir hier vorgeschlagen wurde, völlig naheliegend (unter der Bedingung, dass man unterschiedlich viele Zylinder haben kann, aber die immer den selben Typ haben):

EIne Klasse Motor, die unter anderem die Anzahl der Zylinder und den verwendeten Zylinder enthält.
Eine Klasse Zylinder, die alle Daten für einen Zylinder enthält (u.a. seinen Durchmesser).

Wenn verschiedene Zylinder für einen Motor möglich sind:
Eine Klasse Motor, die eine Liste von Zylindern enthält.
Eine Klasse Zylinder, die alle Daten für einen Zylinder enthält (u.a. seinen Durchmesser).

Gibt es eine Berechnungen für einen Zylinder (Gasgemisch rein, Verbrennung, zurück kommen die Werte), dann gehört das in den Zylinder und wird für den Zylinder berechnet.

Ich bin also ganz bei grubenfox.
Und wenn das wie bei deinem anderen Projekt ist, dann kommen deine ganzen Eigenschaften eines Zylinders aus einer Datenbank. Daraus ergibt sich doch schon deren Zugehörigkeit in die Klasse.

Und angenommen ein Motor würde nur bestimmte Größen von Zylindern zulassen, dann würde die Beschränkung wieder in den Motor gehören und geprüft werden, wenn ein Zylinder hinzugefügt wird.

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 08:58
von Dennis89
Danke für deine Erklärung.
Vorweg: Dass die Vererbung keinen Sinn macht, wurde gesagt und ist wurde auch verstanden?
Ja, das habe ich verstanden und die Idee natürlich auch verworfen.

Okay ich setze das mal so um und schaue ob ich das irgendwie so vereinfacht schreiben kann, dass ihr den Ablauf seht ohne das ich irgendwas ins Netz stelle, das ich nicht darf.

Die Datenbank ist aktuell wieder eine große Excel-Tabelle, ich muss die später erst noch (sinnvoll) erstellen, daher habe ich noch keine Zugehörigkeit und bin noch ganz offen.


Grüße
Dennis

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 10:26
von grubenfox
sparrow hat geschrieben: Montag 28. Oktober 2024, 07:01 Ich bin also ganz bei grubenfox.
Danke, dann bin ich ganz bei sparrow. ;)
Eine Liste mit Zylindern hatte ich auch schon im Hinterkopf. Aber das passte nicht zum prognostizierten "absoluten Chaos mit Listen[sic!] die hin und her gereicht werden". Es gibt eine einzige aktuelle Liste mit Zylindern die herumgereicht wird....

Ob sich das dann so einfach wie in diesem Pseudocode lösen lässt, ist dann die Frage...

Code: Alles auswählen

from functools import partial

def berechne_gasstrom_für_einen_zylinder(ein_zylinder, druck):
    return ein_zylinder.berechne_gasstrom(druck)

def berechne_irgendwie_neuen_druck(liste_mit_gasströmen, aktueller_druck):
    # berechne was
    return neuer_druck_der_hoffentlich_zu einem_besseren_ergebnis_führt
    
def abweichung_vom_gleichgewicht_immer_noch_zu_groß(liste_mit_gasströmen):
    # berechne was
    return True oder False
 
aktueller_druck = 1.0 # irgendwo muss man ja anfangen

liste_mit_gasströmen = map(partial(berechne_gasstrom_für_einen_zylinder, druck = aktueller_druck), liste_mit_zylindern)
while abweichung_vom_gleichgewicht_immer_noch_zu_groß(liste_mit_gasströmen):
    aktueller_druck = berechne_irgendwie_neuen_druck(liste_mit_gasströmen, aktueller_druck)
    liste_mit_gasströmen = map(partial(berechne_gasstrom_für_einen_zylinder, druck = aktueller_druck), liste_mit_zylindern)
Definitiv nicht lauffähig, bei der Nutzung von 'partial' bin ich hier nicht sicher, weil ich 'partial' selbst noch nie genutzt habe und mit dem doppelten 'map(partial(berechne_gasstrom_für_...' nicht schön. Aber halt so die übliche(?) Optimierungsschleife. Der kritische Punkt ist wohl die Berechnung vom neuen (hoffentlich besseren) Druck.

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 10:51
von __blackjack__
Um wirklich eine Liste zu erhalten muss da noch ein `list(…)` drum herum und bei ``list(map(partial(…`` ist die Frage ob eine „list comprehension“ nicht die einfachere/lesbarere Wahl wäre.

Was die doppelte Codezeile angeht: keine kopfgesteuerte Schleife, sondern ``while True:`` und dann in der Schleife die Bedingung mit ``if`` und ggf. ``break``.

Verfasst: Montag 28. Oktober 2024, 10:57
von noisefloor
Hallo,

kann ein Motor denn verschiedene Zylinderdurchmesser haben? Bzw.: ist Motor hier eine Gruppen von Motors wie z.B. "4-Zylinder Turbodiesel" in der Gruppe gibt es konkrete Modelle wie "... mit 1,6l Hubraum", "...mit 2,0l Hubraum", ..., woraus dann z.B. implizit die verschiedenen Kolbendurchmesser resultieren?

Und wenn am Ende eine Datenbank zugrunde liegt, dann würde ich das ganze direkt in ein ORM (wie SQL Alchemy) definieren, dann hat man direkt passende Klassen für die Datenbankstruktur. Das sind ja scheinbar alles 1:n oder n:m Beziehungen.

Gruß, noisefloor

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 12:48
von Dennis89
Danke für eure Antworten.

@grubenfox das passt nicht zu meinem Chaos, weil ich keine Liste von Zylindern hatte. Ich hatte das gestern anders verstanden und daraus kam das Chaos. So wie das jetzt hier heute beschrieben wurde, habe ich es noch nicht umgesetzt, werde ich aber heute oder morgen versuchen.

@noisefloor Ein Motor kann verschiedene Zylinderdurchmesser haben. Es gibt Motormodelle, diese unterscheiden sich in der Anordnung der Zylinder (Reihe, V, W) und jeder Motor kann, unabhängig von der Bauform, unterschiedliche Zylinderdurchmesser haben. Also zum Beispiel kann ein Reihenmotor 2 Zylinder haben, einer hat einen Durchmesser von 80mm und einer hat einen Durchmesser von 65mm.

SQLAlchemy würde ich gerne wieder verwenden, da ich das in meinem letzten Projekt auch schon verwendet hatte und auch alles irgendwann mal vereint werden soll.


Danke und Grüße
Dennis

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 16:25
von kbr
Dennis89 hat geschrieben: Montag 28. Oktober 2024, 12:48Also zum Beispiel kann ein Reihenmotor 2 Zylinder haben, einer hat einen Durchmesser von 80mm und einer hat einen Durchmesser von 65mm.
Bislang hatte ich bei Verbrennungsmotoren nur an die Geometrie gedacht (Reihe, Boxer, Stern, Kurbelwelle etc) wenn es z.B. um Eigenschaften wie Drehmomentverteilung geht, aber nicht an unterschiedliche Kolbendurchmesser innerhalb eines Motors. Ist so was üblich, oder eher ein Sonderfall? Und wann braucht man so etwas?

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 16:47
von DeaD_EyE
kbr hat geschrieben: Montag 28. Oktober 2024, 16:25 Ist so was üblich, oder eher ein Sonderfall? Und wann braucht man so etwas?
Ein Motor mit unterschiedlichen Kolbendurchmessern würde sehr unruhig laufen. Kleinerer Kolben => weniger Kraft.

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Montag 28. Oktober 2024, 17:04
von sparrow
@Dennis89: Ist ein Motor nur eine Hülle für beliebig viele beliebige Zylinder oder gibt es bestimmte Motoren, die nur bestimmte Konfigurationen zulassen?

Also im Sinne von Motorblock mit der internen ID X hat Platz für zwei Zylinder, Durchmesser sind egal. Y hat Platz für 4 Zylinder, ....

Re: Code-Strukturierung, macht Vererbung hier Sinn?

Verfasst: Dienstag 29. Oktober 2024, 07:27
von Dennis89
Guten Morgen,

@kbr Der Motor ist nicht real, deswegen schrieb ich eingangs:

Code: Alles auswählen

...und man kann es vielleicht mit einen Motor wieder ganz gut erklären.
Sinn würde das evtl nur machen, wenn man die einzelnen Zylinder unabhängig voneinander betreiben könnt.

@sparrow Ja je nach Motorblock ist die Anzahl der Zylinder begrenzt, dein letzter Satz beschreibt es richtig.

Ich habe nun versucht, das ganze so zu schreiben, das ich es hier zeigen kann. Das heißt aber auch, dass die Rechnungen teilweise erfunden sind und *keinen* Sinn ergeben. Aber in der Funktion `get_norm_volume_flow` sieht man wie die Werte ineinander übergehen und was ich damit meinte, das ich für die Berechnung den Ein- und Auslass solange anpassen muss, bis sich ein Gleichgewicht einstellt.
Ich weis das man keine Namen nummeriert, die Funktion kann so auch nicht bleiben, weil die nur für zwei Zylinder funktioniert und wenn ich drei habe, dann muss sich das Gleichgewicht zwischen allen dreien einstellen. Das heißt, die wird so oder so neu und anders geschrieben, sobald ich weis wie.

Ich habe aber auch das Gefühl, dass nicht alle Methoden in der richtigen Klasse sind bzw. ob die vielleicht nicht einfach Funktionen sein sollten. Hmm irgendwie habe ich noch kein roten Faden.

Code: Alles auswählen

#!/usr/bin/env python

from math import pi
from functools import cached_property

from attr import define, field



@define
class Cylinder:
    piston_diameter = field()
    xyz_factor = field()
    abc_factor = field()

    def _piston_area(self):
        return pi / 4 * self.piston_diameter**2

    def _volume(self, stroke):
        return 2 * stroke * self._piston_area()

    def _volume_flow(self, speed, stroke):
        return self._volume(stroke) * speed

    def _volume_factor(self, inlet, outlet, polytrope):
        return 1 - self.xyz_factor * (
            self.abc_factor * (outlet / inlet) ** (1 / polytrope) - 1
        )

    def volume_flow(
        self,
        inlet,
        outlet,
        polytrope,
        speed,
        stroke,
        temperature_factor,
    ):
        return (
            self._volume_flow(speed, stroke)
            * self.xyz_factor
            * self._volume_factor(inlet, outlet, polytrope)
            * temperature_factor
        )


@define
class Motor:
    cylinders: list[Cylinder] = field()
    stroke = field()
    speed = field()
    inlet = field()
    outlet = field()
    inlet_temperature = field()
    gas = field()

    @property
    def piston_speed(self):
        return 2 * self.stroke * 2 * self.speed

    @cached_property
    def another_value(self):
        return (self.inlet_temperature - 273.15) / (
            237.3 + (self.inlet_temperature - 273.15)
        )

    def norm_volume_flow(self, inlet, another_value, volume_flow):
        return self.inlet * (inlet - self.gas.humidity * another_value) * volume_flow

    @staticmethod
    def polytrop(inlet, outlet):
        # Calculation with inlet and outlet
        return 42

    def temperature_factor(self, inlet, outlet, piston_diameter, xyz_factor):
        return (
            xyz_factor
            * piston_diameter
            * self.gas.density
            * self.piston_speed
            * piston_diameter
            * self.stroke
            / piston_diameter
            * outlet
            / inlet
        )


def get_norm_volume_flow(motor, cylinders):
    cylinder_1, cylinder_2 = cylinders
    start = motor.inlet + 100000
    inlet_1 = start
    outlet_2 = start
    while True:
        temperature_factor = motor.temperature_factor(
            motor.inlet,
            inlet_1,
            cylinder_1.piston_diameter,
            cylinder_1.xyz_factor,
        )
        polytrope = motor.polytrop(motor.inlet, inlet_1)
        flow = cylinder_1.volume_flow(
            motor.inlet,
            inlet_1,
            polytrope,
            motor.speed,
            motor.stroke,
            temperature_factor,
        )

        norm_volume_flow_1 = motor.norm_volume_flow(
            motor.inlet,
            motor.another_value,
            flow,
        )

        temperature_factor = motor.temperature_factor(
            outlet_2,
            motor.outlet,
            cylinder_2.piston_diameter,
            cylinder_2.xyz_factor,
        )
        polytrope = motor.polytrop(outlet_2, motor.outlet)

        flow = cylinder_2.volume_flow(
            outlet_2,
            motor.outlet,
            polytrope,
            motor.speed,
            motor.stroke,
            temperature_factor,
        )

        norm_volume_flow_2 = motor.norm_volume_flow(outlet_2, motor.another_value, flow)

        if abs(norm_volume_flow_1 - norm_volume_flow_2) < 0.0001:
            return norm_volume_flow_1
        inlet_1 += 1
        outlet_2 += 1


def main():
    pass


if __name__ == "__main__":
    main()

Danke und Grüße
Dennis