Source code for roxieapi.input.builder
import copy
import logging
import os
from pathlib import Path
from typing import List
import jinja2
import pandas as pd
from roxieapi.commons.types import BrickData
from roxieapi.input.parser import (
RoxieInputParser,
convert_bottom_header_table_to_str,
convert_list_to_str,
convert_table_to_str,
)
[docs]
class RoxieInputBuilder:
"""Class RoxieInputBuilder builds a ROXIE input"""
DEFAULT_VERSION = "23.9.0"
DEFAULT_FLAGS = {
"LEND": False,
"LWEDG": False,
"LPERS": False,
"LQUENCH": False,
"LALGO": False,
"LQUENCH0D": False,
"LMIRIRON": False,
"LBEMFEM": False,
"LPSI": False,
"LSOLV": False,
"LIRON": False,
"LMORPH": False,
"LHMO": False,
"LHARD": False,
"LPOSTP": False,
"LPEAK": False,
"LINMARG": False,
"LMARG": False,
"LSELF": False,
"LMQE": False,
"LINDU": False,
"LEDDY": False,
"LSOLE": False,
"LFLUX": False,
"LFIELD3": False,
"LSELF3": False,
"LBRICK": False,
"LLEAD": False,
"LVRML": False,
"LOPERA": False,
"LOPER20": False,
"LANSYS": False,
"LRX2ANS": False,
"LANS2RX": False,
"LDXF": False,
"LMAP2D": False,
"LMAP3D": False,
"LEXPR": False,
"LFIL3D": False,
"LFIL2D": False,
"LCNC": False,
"LANSYSCN": False,
"LWEIRON": False,
"LCATIA": False,
"LEXEL": False,
"LQVOLT": False,
"LFORCE2D": False,
"LQUNPLOT": False,
"LGRAPHCSV": False,
"LAXIS": False,
"LIMAGX": False,
"LIMAGY": False,
"LRAEND": False,
"LMARKER": False,
"LROLER2": False,
"LROLERP": False,
"LIMAGZZ": False,
"LSUPP": False,
"LSTEP": False,
"LSKIPDPL": False,
"LIFF": False,
"LICCA": False,
"LICC": False,
"LICCIND": False,
"LITERNL": False,
"LTOPO": False,
"LQUEN3": False,
"LAYER": False,
"LEULER": False,
"LHEAD": False,
"LPLOT": False,
"LVERS52": False,
"LHARM": False,
"LMATRF": False,
"LF3LIN": False,
"LKVAL": False,
"LSKIPTPL": False,
}
def __init__(self) -> None:
self.version = RoxieInputBuilder.DEFAULT_VERSION
self.comment = ""
self.bhdata_path = ""
self.cadata_path = ""
self.iron_path = ""
self.flags = copy.copy(RoxieInputBuilder.DEFAULT_FLAGS)
self.global2doption = pd.DataFrame()
self.global3d = pd.DataFrame()
self.block = pd.DataFrame()
self.blockoption = pd.DataFrame()
self.block3d = pd.DataFrame()
self.blockoption3d = pd.DataFrame()
self.lead = pd.DataFrame()
self.brick: List[BrickData] = []
self.ironyokeoptions = pd.DataFrame()
self.ironyoke = pd.DataFrame()
self.extrusion = pd.DataFrame()
self.permanentmag2 = pd.DataFrame()
self.permanentmag1 = pd.DataFrame()
self.layer = pd.DataFrame()
self.algo = pd.DataFrame()
self.design = pd.DataFrame()
self.euler = pd.DataFrame()
self.peak: List[int] = []
self.timetable2 = pd.DataFrame()
self.timetable1 = pd.DataFrame()
self.eddy = pd.DataFrame()
self.eddyoptions = pd.DataFrame()
self.quenchg = pd.DataFrame()
self.quenchen = pd.DataFrame()
self.quenchtm = pd.DataFrame()
self.quenchp = pd.DataFrame()
self.quenchs = pd.DataFrame()
self.harmonictable = pd.DataFrame()
self.matrf = pd.DataFrame()
self.matrf_coordsystem = 1 # 1 for cartesian, 2 for polar
self.linefield = pd.DataFrame()
self.kvalues = pd.DataFrame()
self.harmonicoption = pd.DataFrame()
self.graph = pd.DataFrame()
self.graphoption = pd.DataFrame()
self.plot2d = pd.DataFrame()
self.plot2doption = pd.DataFrame()
self.plot3d = pd.DataFrame()
self.plot3doption = pd.DataFrame()
self.ansysoptions = pd.DataFrame()
self.objective = pd.DataFrame()
self.quench0d = pd.DataFrame()
self.logger = logging.getLogger("RoxieInputBuilder")
[docs]
def set_flag(self, flag_name: str, flag_value: bool) -> "RoxieInputBuilder":
"""Method setting a flag in a ROXIE input file. An error is thrown if a flag does not exist
:param flag_name: name of a flag
:param flag_value: value of a flag
:return: an updated RoxieInputBuilder instance
"""
if flag_name in self.flags.keys():
self.flags[flag_name] = flag_value
else:
raise KeyError("Key")
return self
[docs]
def update_version(self):
if self.version < "10.1":
# Harmonic Table
if not self.harmonictable.empty:
self.harmonictable.insert(loc=1, column="type", value=1)
self.harmonictable.insert(loc=4, column="s1", value=0)
self.harmonictable.insert(loc=5, column="s2", value=0)
if self.version < "10.1.2":
# Ironyokeoptions handled in parser
# Matrf handled in parser
pass
if self.version < "10.1.3":
if self.flags["LSTEP"]:
self.timetable1.insert(loc=8, column="nsteps", value=0)
if self.version < "22.0":
# Block
if self.flags["LEND"]:
self.block.insert(loc=12, column="disc", value=21)
# Block/Block3D helix
if "4" in self.block["type"]:
self.logger.warning(
"Helix definition in block data from a Datafile < 22.0 found. "
+ "The definition of Helices changed. Please check your block data"
)
# Quench0D
if not self.quench0d.empty:
self.quench0d.insert(loc=1, column="tempq", value=0.0)
self.quench0d.drop("indu", axis=1, inplace=True)
self.quench0d.insert(loc=4, column="dtdt", value=0.0)
self.quench0d.insert(loc=5, column="deltm", value=0.0)
self.quench0d.insert(loc=6, column="currqm", value=0.0)
# update flags
old_flags = self.flags.keys() - self.DEFAULT_FLAGS.keys()
for old_flag in old_flags:
del self.flags[old_flag]
new_flags = self.DEFAULT_FLAGS.keys() - self.flags.keys()
for new_flag in new_flags:
self.flags[new_flag] = self.DEFAULT_FLAGS[new_flag]
# Set the new version of the datafile
self.version = self.DEFAULT_VERSION
[docs]
def build(self, output_path: Path) -> None:
"""Method building a ROXIE input based on a template file
:param output_path: an output path for the input .data file
"""
output_str = self.prepare_data_file_str_from_template()
with open(output_path, "wb") as input_file:
input_file.write(bytes(output_str, "utf-8").replace(b"\r\n", b"\n"))
[docs]
def prepare_data_file_str_from_template(self) -> str:
path = Path(os.path.dirname(__file__))
template_loader = jinja2.FileSystemLoader(searchpath=path)
template_env = jinja2.Environment(loader=template_loader)
template_env.globals["convert_bottom_header_table_to_str"] = (
convert_bottom_header_table_to_str
)
template_env.globals["convert_table_to_str"] = convert_table_to_str
template_env.globals["convert_flag_dct_to_str"] = (
RoxieInputBuilder.convert_flag_dct_to_str
)
template_env.globals["convert_list_to_str"] = convert_list_to_str
template_env.globals["str"] = str
template_env.globals["len"] = len
TEMPLATE_FILE = "roxie_template.data.j2"
template = template_env.get_template(TEMPLATE_FILE)
return template.render(input=self)
[docs]
@staticmethod
def convert_flag_dct_to_str(flags: dict) -> str:
"""Static method converting a dictionary with flags into a formatted string
:param flags: a dictionary with flags
:return: a formatted string representation of the dictionary with flags
"""
COLUMN_WIDTH = 15
flag_per_line_count = 1
flag_str = " "
for key, value in flags.items():
temp = "%s=%s" % (key, "T" if value else "F")
temp += (COLUMN_WIDTH - len(temp)) * " "
if flag_per_line_count < 6:
flag_str += temp
flag_per_line_count += 1
else:
flag_str += temp + "\n "
flag_per_line_count = 1
flag_str += "\n /"
return flag_str
[docs]
@staticmethod
def from_datafile(filename):
"""Constructs a RoxieInputBuilder, initializing its values from a .data file
:param filename: The .data file
:return a constructed RoxieInputBuilder object
"""
rip = RoxieInputParser.from_datafile(filename)
b = RoxieInputBuilder()
b.version = rip.version
b.comment = rip.comment
b.cadata_path = rip.cadata_path
b.bhdata_path = rip.bhdata_path
b.iron_path = rip.iron_path
b.flags = rip.options
b.global2doption = rip.get_block("GLOBAL2DOPTION")
b.global3d = rip.get_block("GLOBAL3D")
b.block = rip.get_block("BLOCK")
b.blockoption = rip.get_block("BLOCKOPTION")
b.block3d = rip.get_block("BLOCK3D")
b.blockoption3d = rip.get_block("BLOCKOPTION3D")
b.lead = rip.get_block("LEAD")
b.brick = rip.get_bricks()
b.ironyokeoptions = rip.get_block("IRONYOKEOPTIONS")
b.ironyoke = rip.get_block("IRONYOKE")
b.extrusion = rip.get_block("EXTRUSION")
b.permanentmag2 = rip.get_block("PERMANENTMAG2")
b.permanentmag1 = rip.get_block("PERMANENTMAG1")
b.layer = rip.get_block("LAYER")
b.algo = rip.get_block("ALGO")
b.design = rip.get_block("DESIGN")
b.euler = rip.get_block("EULER")
b.peak = rip.get_peak()
b.timetable2 = rip.get_block("TIMETABLE2")
b.timetable1 = rip.get_block("TIMETABLE1")
b.eddy = rip.get_block("EDDY")
b.eddyoptions = rip.get_block("EDDYOPTONS")
b.quenchg = rip.get_block("QUENCHG")
b.quenchen = rip.get_block("QUENCHEN")
b.quenchtm = rip.get_block("QUENCHTM")
b.quenchp = rip.get_block("QUENCHP")
b.quenchs = rip.get_block("QUENCHS")
b.harmonictable = rip.get_block("HARMONICTABLE")
b.matrf_coordsystem = rip.matrf_coordsystem
b.matrf = rip.get_block("MATRF")
b.linefield = rip.get_block("LINEFIELD")
b.kvalues = rip.get_block("KVALUES")
b.harmonicoption = rip.get_block("HARMONICOPTION")
b.graph = rip.get_block("GRAPH")
b.graphoption = rip.get_block("GRAPHOPTION")
b.plot2d = rip.get_block("PLOT2D")
b.plot2doption = rip.get_block("PLOT2DOPTION")
b.plot3d = rip.get_block("PLOT3D")
b.plot3doption = rip.get_block("PLOT3DOPTION")
b.objective = rip.get_block("OBJECTIVE")
b.ansysoptions = rip.get_block("ANSYSOPTIONS")
b.quench0d = rip.get_block("QUENCH0D")
return b