From cf4188789b79e0d6e4070e4de37fc250f9cd84ac Mon Sep 17 00:00:00 2001 From: Zi-Jing Zhang Date: Mon, 27 Nov 2023 19:32:29 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=8F=AF=E8=AF=86=E5=88=AB=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E7=9A=84=E6=9D=90=E8=B4=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _base.py | 5 +--- geom_parser.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++---- grd_parser.py | 64 ++++++++++++++++++++++++++++---------------------- log_parser.py | 2 +- 4 files changed, 98 insertions(+), 37 deletions(-) diff --git a/_base.py b/_base.py index ad533bd..fe0bc0e 100644 --- a/_base.py +++ b/_base.py @@ -36,10 +36,7 @@ frequent_used_unit_to_SI_unit = { } -class MaterialType(enum.Enum): - CONDUCTOR = 0 - DIELECTRIC = 1 - VOID = 2 + class ParserBase: """ diff --git a/geom_parser.py b/geom_parser.py index 5219ea8..64c31cb 100644 --- a/geom_parser.py +++ b/geom_parser.py @@ -7,6 +7,9 @@ import os.path import matplotlib +import numpy + +from _logging import logger matplotlib.use("TkAgg") matplotlib.rcParams['font.family'] = 'SimHei' @@ -21,9 +24,28 @@ import matplotlib.pyplot as plt import filenametool import grd_parser import log_parser +import typing +import shapely.geometry +import enum + +class GEOM: + class Type(enum.Enum): + CONDUCTOR = 0 + DIELECTRIC = 1 + # VOID = 2 + VACUUM = 3 + PORT = 4 + AXIAL = 5 -class Geom: + colormap = { + Type.CONDUCTOR: (190, 190, 190, 1), # RGBA + Type.DIELECTRIC: (0, 255, 127, 1), + Type.VACUUM: (255, 255, 255, 1), + Type.PORT: (255, 255, 0, 1), + + } + MAX_CHAR_OF_VALUE_IN_STRUCTURE_GENERATOR_RESULT = 16 def __init__(self, filename): """ :param filename: 后缀无所谓 @@ -33,10 +55,44 @@ class Geom: filenametool.ExtTool(filename_no_ext).get_name_with_ext(filenametool.ExtTool.FileType.grd)) self.log = log_parser.LOG( filenametool.ExtTool(filename_no_ext).get_name_with_ext(filenametool.ExtTool.FileType.log)) + self._shapes = self.grd.parse_geom() + # 因log文件中structure generator result表的长度限制,截取每项的前几个字符 + self.shapes = {key[:GEOM.MAX_CHAR_OF_VALUE_IN_STRUCTURE_GENERATOR_RESULT] : self._shapes[key ] for key in self._shapes} - def plot(self, ax: plt.Axes)->plt.Axes: + def plot(self, ax: plt.Axes) -> plt.Axes: """ - :return: ax """ - # TODO + for i in self.log.geom_structure_generator_result.index: + objname = self.log.geom_structure_generator_result['ObjectName'][i] + # logger.info(objname) + self.plot_shape(ax, + self.shapes.get(objname, objname), + GEOM.Type[self.log.geom_structure_generator_result['Type'][i]]) + return ax + + @staticmethod + def plot_shape( + ax: plt.Axes, + shape: typing.Union[shapely.geometry.Polygon, shapely.geometry.Point, str], + material: Type): + if isinstance(shape, str): + logger.warning("Object '%s' is ignored" % shape) + return ax + if isinstance(shape, shapely.geometry.Point): + ax.scatter(*shape.xy) + return ax + + _color = GEOM.colormap[material] + color = numpy.array(_color) / (255, 255, 255, 1) + ax.fill(*shape.exterior.xy, facecolor=color) + return ax + + +if __name__ == '__main__': + plt.ion() + # filename = r"D:\MagicFiles\CherenkovAcc\cascade\min_case_for_gradient_test\test_diffraction-23.grd" + filename = r"E:\GeneratorAccelerator\Genac\optmz\Genac10G50keV\粗网格\单独处理\Genac10G50keV2.grd" + geom = GEOM(filename) + plt.figure() + geom.plot(plt.gca()) diff --git a/grd_parser.py b/grd_parser.py index c9c9740..7e51f46 100644 --- a/grd_parser.py +++ b/grd_parser.py @@ -93,34 +93,44 @@ class GRD(_base.ParserBase): super(GRD, self).__init__(filename) self.parse_all_range_datas() self.obs: typing.Dict[str, typing.Dict] = {} - self.parse_all_observes() - def plot_geom(self, ax: plt.Axes): + + def parse_geom(self) -> typing.Dict[str, + typing.Union[shapely.geometry.Polygon, shapely.geometry.Point]]: + self._parse_BOUNDARIES() supported_aotype = {GRD.Object_.AOTYPE.XCONFORMAL2, GRD.Object_.AOTYPE.XLINE} - mask = pandas.Series([False] * self.objects_aobj_aotype_iotype.shape[0]) + mask = pandas.Series([False] * self._objects_aobj_aotype_iotype.shape[0]) for aotype in supported_aotype: - mask = mask | (self.objects_aobj_aotype_iotype[1] == aotype.name) - supported_xodata = self.objects_xodata.loc[mask] + mask = mask | (self._objects_aobj_aotype_iotype[1] == aotype.name) + supported_xodata = self._objects_xodata.loc[mask] supported_obj_names_indexes_type = {name: [[], GRD.Object_.AOTYPE.UNKNOWN] for name in - self.objects_aobj_aotype_iotype[0][mask].unique()} + self._objects_aobj_aotype_iotype[0][mask].unique()} for i in supported_xodata.index: - supported_obj_names_indexes_type[self.objects_aobj_aotype_iotype[0][i]][0].append(i) - supported_obj_names_indexes_type[self.objects_aobj_aotype_iotype[0][i]][1] = GRD.Object_.AOTYPE[ - self.objects_aobj_aotype_iotype[1][i]] - polygons = [] + supported_obj_names_indexes_type[self._objects_aobj_aotype_iotype[0][i]][0].append(i) + supported_obj_names_indexes_type[self._objects_aobj_aotype_iotype[0][i]][1] = GRD.Object_.AOTYPE[ + self._objects_aobj_aotype_iotype[1][i]] + polygons = {} for objname in supported_obj_names_indexes_type: if supported_obj_names_indexes_type[objname][1] == GRD.Object_.AOTYPE.XLINE: - polygons.append(GRD.Object_.build_XLINE( - self.objects_xodata.loc[supported_obj_names_indexes_type[objname][0]].values[:, 1:5])) + polygons[objname] = (GRD.Object_.build_XLINE( + self._objects_xodata.loc[supported_obj_names_indexes_type[objname][0]].values[:, 1:5])) elif supported_obj_names_indexes_type[objname][1] == GRD.Object_.AOTYPE.XCONFORMAL2: - polygons.append(GRD.Object_.build_XCONFORMAL2( - *self.objects_xodata.loc[supported_obj_names_indexes_type[objname][0]].values[0, 1:5])) - for polygon in polygons: - ax.plot(*polygon.exterior.xy, ) + polygons[objname] = (GRD.Object_.build_XCONFORMAL2( + *self._objects_xodata.loc[supported_obj_names_indexes_type[objname][0]].values[0, 1:5])) + return polygons + + def plot_geom(self, ax: plt.Axes): + polygons = self.parse_geom() + for objname in polygons: + ax.plot(*polygons[objname].exterior.xy, ) - def parse_geom_data(self): + def _parse_BOUNDARIES(self): + """ + 初步解析BOUNDARIES块 + :return: + """ geom_data_str = self.blocks_groupby_type[self.BlockType.BOUNDARIES][0] geom_data_str_linelist = geom_data_str.splitlines(True) objects_array_shape = [int(num) for num in @@ -135,16 +145,14 @@ class GRD(_base.ParserBase): i_AOBJ_AOTYPE_IOTYP_start:i_AOBJ_AOTYPE_IOTYP_start + objects_array_shape[1]] - self.objects_xodata = pandas.read_csv(StringIO(''.join(objects_xodata_str_linelist)), sep=r'\s+', - header=None, on_bad_lines='skip') - self.objects_kodata = pandas.read_csv(StringIO(''.join(objects_kodata_str_linelist)), sep=r'\s+', - header=None, on_bad_lines='skip') - self.objects_aobj_aotype_iotype = pandas.read_csv(StringIO(''.join(objects_AOBJ_AOTYPE_IOTYP_str_linelist)), - sep=r'\s+', - header=None, on_bad_lines='skip') - self.objects_xodata[0] = self.objects_xodata[0].astype(int) - - pass + self._objects_xodata = pandas.read_csv(StringIO(''.join(objects_xodata_str_linelist)), sep=r'\s+', + header=None, on_bad_lines='skip') + self._objects_kodata = pandas.read_csv(StringIO(''.join(objects_kodata_str_linelist)), sep=r'\s+', + header=None, on_bad_lines='skip') + self._objects_aobj_aotype_iotype = pandas.read_csv(StringIO(''.join(objects_AOBJ_AOTYPE_IOTYP_str_linelist)), + sep=r'\s+', + header=None, on_bad_lines='skip') + self._objects_xodata[0] = self._objects_xodata[0].astype(int) def parse_all_observes(self): if not self.obs: @@ -244,7 +252,7 @@ if __name__ == '__main__': # filename = r"D:\MagicFiles\CherenkovAcc\cascade\min_case_for_gradient_test\test_diffraction-23.grd" grd = GRD(filename) - grd.parse_geom_data() + # grd._parse_BOUNDARIES() plt.ion() plt.figure() grd.plot_geom(plt.gca()) diff --git a/log_parser.py b/log_parser.py index b40f317..ab114f4 100644 --- a/log_parser.py +++ b/log_parser.py @@ -25,7 +25,7 @@ class LOG: self.text = f.read() t1 = time.time() logger.info("将文件%s读入内存(未处理)耗时:%.2f" % (filename, t1 - t)) - self.geom_structure = self.parse_geom_generator_result(self.text) + self.geom_structure_generator_result = self.parse_geom_generator_result(self.text) @staticmethod def parse_geom_generator_result(text: str) -> pandas.DataFrame: -- Gitee From a4f6d3543a8c8660b961efcb706aee3353bf1139 Mon Sep 17 00:00:00 2001 From: Zi-Jing Zhang Date: Mon, 27 Nov 2023 20:10:22 +0800 Subject: [PATCH 2/2] Update README --- .../03843dd168382254da1ce501cce9a4d1.png | Bin 0 -> 15887 bytes .../9d6730f8c7ae9904e71d4806d55abb68.png | Bin 0 -> 9379 bytes README.md | 17 +- geom_parser.py | 4 +- temp.txt | 14405 ---------------- 5 files changed, 18 insertions(+), 14408 deletions(-) create mode 100644 .md_attachments/03843dd168382254da1ce501cce9a4d1.png create mode 100644 .md_attachments/9d6730f8c7ae9904e71d4806d55abb68.png delete mode 100644 temp.txt diff --git a/.md_attachments/03843dd168382254da1ce501cce9a4d1.png b/.md_attachments/03843dd168382254da1ce501cce9a4d1.png new file mode 100644 index 0000000000000000000000000000000000000000..7a43a10d9a6afa77e2a4a4176d434cde5802a1c9 GIT binary patch literal 15887 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%0A_@nuOXf(6ltA7a2O{N1(?RCQsPm&JzaA3Df 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 lYsG)LGe!PieA{MV1Lb~;1BZR5K|