Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
utilities.py 8.95 KiB
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
This module contains usefule utilities for many
different python scripts
"""
from __future__ import print_function
import re
from functools import wraps
from subprocess import Popen, PIPE
from sys import __stdout__
from os import mkdir
from os.path import dirname, exists
from typing import (
Iterable, Optional, List, Callable, TypeVar, Union, Any, Tuple)
from pathlib import Path
from collections import OrderedDict
from urllib3.exceptions import MaxRetryError
from python_translator import Translator
def running_average(X: List[float], n: int) -> List[float]:
"""creates a running average of X with n entries in both dircetions"""
X_new = []
for i in range(n):
X_new += [sum(X[0: i + 1]) / (i + 1)]
for i in range(n, len(X) - n):
X_new += [sum(X[i - n: i + n + 1]) / (2 * n + 1)]
for i in range(len(X) - n, len(X)):
X_new += [sum(X[2 * i - len(X) + 1:]) / ((len(X) - (i + 1)) * 2 + 1)]
return X_new
def quality_of_fit(X: List[float], Y: List[float]) -> float:
"""calculates the quality of a fit 'bestimmtheitsmass'"""
mean_x = sum(X) / len(X)
return sum(x ** 2 - mean_x ** 2 for x in X)\
/ sum(x ** 2 - mean_x ** 2 for x in Y)
Return = TypeVar("Return")
def print_redirect(f: Callable[..., Return]) -> Callable[..., Return]:
"""
wraps print to print to both stdout and __stdout__
the reason for doing that is that abaqus replaces
stdout and prints everything to abaqus
this way everything can be seen both in the command line and in abaqus
"""
@wraps(f)
def inner_function(*args: Any, **argv: Any) -> Return:
f(*args, **argv)
for i, arg in enumerate(args):
if isinstance(type, arg):
del arg[i]
for _, val in argv.items():
if isinstance(type, val):
del val
argv["file"] = __stdout__
f(*args, **argv)
try:
return f(*args, **argv)
except TypeError:
print("The argument 'file' is twice in a print statement")
raise
return inner_function
def filter_function(x: str) -> bool:
"""filter function in order to remove unused
arguments from this script before parsing"""
if ":" in x or "rwth" in x:
return False
analysed_item = x.replace("--", ".")
analysed_item = analysed_item.replace("-", "!")
if len(analysed_item) > 2\
and "." not in analysed_item\
and "!" in analysed_item:
return False
return True
def filter_argv(X: List[str]) -> List[str]:
"""removes unessecery entries from
argv which have been generated by abaqus"""
Y: List[str] = list(X)
for i, x in enumerate(X):
if not filter_function(x):
del Y[i]
if i < len(Y):
del Y[i + 1]
return Y
def dumb_plot(X: List[float], Y: List[float],
title: str = "title", log: bool = False) -> None:
"""plot X and Y using dumb gnuplot"""
try:
with Popen(["gnuplot"], stdin=PIPE) as gnuplot:
assert gnuplot, """Gnuplot could not be started."""
assert gnuplot.stdin, """Input to Gnuplot could not be found."""
gnuplot.stdin.write(bytes("set term dumb 79 25\n", "utf-8"))
if log:
gnuplot.stdin.write(bytes("set logscale xy\n", "utf-8"))
gnuplot.stdin.write(
bytes(
f"""plot '-' using 1:2 title '{title}'
with linespoints \n""",
"utf-8"
)
)
for x, y in zip(X, Y):
gnuplot.stdin.write(bytes(f"{x} {y}\n", "utf-8"))
gnuplot.stdin.write(bytes("e\n", "utf-8"))
gnuplot.stdin.flush()
except FileNotFoundError:
print("There is no installed instance of gnuplot")
def read_file(filename: Union[str, Path],
header: int = 0,
type_: type = float) -> Tuple[List[float], ...]:
"""read a file with given filename into
a python-tuple. Skip n='header' lines in the beginning
of the document"""
# reads a given file and returns lists
lists: List[List[float]] = []
with open(filename, "r", encoding="utf-8") as input_file:
for i, line in enumerate(input_file):
if i < header:
continue
lists += [[type_(v) for v in line.split()]]
return tuple(list(v) for v in zip(*lists))
def write_file(filename: Union[Path, str],
*args: Iterable[float],
title: Optional[str] = None) -> None:
"""write the rows given in 'arga' to a file"""
# write data to a file
if not any(args[0]):
raise ValueError("Tried to write an empty row to a file.")
if isinstance(filename, str):
filename = Path(filename)
with open(filename, "w", encoding="utf-8") as output_file:
if title is not None:
output_file.write(title + "\n")
for row in zip(*args):
output_file.write(" ".join(str(r) for r in row) + "\n")
def mkdir_p(foldername: str) -> None:
"""creates a new folder if the folder does not exist"""
try:
if exists(foldername):
return
mkdir(foldername)
except IOError as e:
# recursive creation of needed folders
if e.errno != 2:
raise
mkdir_p(dirname(foldername))
mkdir_p(foldername)
def trash_remover(func: Callable[..., Tuple[Return, ...]])\
-> Callable[..., Return]:
"""only keeps the first output of a given function"""
@wraps(func)
def inner_function(*args: Any, **kwargs: Any) -> Return:
result = func(*args, **kwargs)
return result[0]
return inner_function
def use_translator(string: str, lang1: str, lang2: str) -> str:
"""
Translate the given input string from lang2 to lang1 using google
translate.
"""
# one letter strings
if len(string) <= 1:
return string
if r"\times" in string:
return string
try:
translator = Translator()
result: str
result = translator.translate(string, lang1, lang2)
except (OSError, MaxRetryError):
return string
return str(result)
def translate(string: str, reverse: bool = False) -> str:
"""translates a string from english to german
@input string any string wich contains specific english words
@input reverse translate ger->en if set to true
@return the german translation of the same string"""
if r"$" in string or not string:
return string
if reverse:
string = re.sub(r'(\d+),(\d+)', r'\1\.\2', string)
else:
string = re.sub(r'(\d+)\.(\d+)', r'\1,\2', string)
_dict: dict[str, str] = OrderedDict({
"leakage": "Leckage",
"contact pressure": "Kontaktdruck",
"fluid pressure": "Fluiddruck",
"pressure": "Druck",
"density": "Dichte",
"roundness": "Rundheit",
"eccentricity": r"Exzentrizit\"at",
"contact area": r"Kontaktoberfl\"ache",
"area": r"Fl\"ache",
"maximal": "Maximale",
"time": "Zeit",
"normal-force": "Normalkraft",
"normal force": "Normalkraft",
"total force": "Gesamtkraft",
"force": "Kraft",
"distance": "Abstand",
"position": "Position",
"contact broadness": "Kontaktbreite",
"broadness": "Breite",
"contact": "Kontakt-",
"seat": "Sitz",
"ball": "Kugel",
"high": "hoch",
"low": "tief",
"elastic": "elastisch",
"plastic": "plastisch",
"angle": "Winkel",
"degree": "Grad",
"deg": "Grad",
"hard": "hart",
"soft": "weich",
"fit": "Fit",
"data": "Messwerte",
"velocity": "Geschwindigkeit",
"measurement": "Messung",
"experiment": "Experiment",
"simulation": "Simulation",
"analytical": "analytisch",
"signal": "Signal",
"valve control": "Ventilansteuerung",
"off": "zu",
"on": "auf",
"status": "Zustand",
"valve": "Ventil",
"relative pressure": "Relativdruck",
"absolute pressure": "Absolutdruck",
"relative": "relativ",
"absolute": "absolut",
"plot": "Graph",
"orifice": "Blende",
"Hagen–Poiseuille": "Hagen-Poiseuille",
"test": "Test"
})
if not reverse and r"\times" not in string:
for key, value in _dict.items():
if key in string.lower():
string = re.sub(
key, value, string,
flags=re.IGNORECASE)
break
else:
string = use_translator(string, "german", "english")
else:
for key, value in _dict.items():
if value.lower() in string.lower():
string = string.lower().replace(value.lower(), key.lower())
break
else:
string = use_translator(string, "english", "german")
return string