From eac600f7aecfe11c1bf9ee968aef8fa7312c9142 Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 27 Dec 2024 13:09:57 -0600 Subject: [PATCH 01/15] split MagnetSet and MagnetCoil --- Examples/parastell_cubit_example.py | 2 +- Examples/radial_distance_example.py | 2 +- parastell/cubit_io.py | 35 ++ parastell/magnet_coils.py | 536 +++++++++++++++++----------- parastell/parastell.py | 17 +- parastell/radial_distance_utils.py | 29 +- tests/test_magnet_coils.py | 134 +++++-- tests/test_parastell.py | 47 ++- 8 files changed, 543 insertions(+), 259 deletions(-) diff --git a/Examples/parastell_cubit_example.py b/Examples/parastell_cubit_example.py index bb8597b..c38b9a1 100644 --- a/Examples/parastell_cubit_example.py +++ b/Examples/parastell_cubit_example.py @@ -56,7 +56,7 @@ thickness = 50.0 toroidal_extent = 90.0 # Construct magnets -stellarator.construct_magnets( +stellarator.construct_magnets_from_filaments( coils_file, width, thickness, toroidal_extent, sample_mod=6 ) # Export magnet files diff --git a/Examples/radial_distance_example.py b/Examples/radial_distance_example.py index 1d3c3f2..70e83e6 100644 --- a/Examples/radial_distance_example.py +++ b/Examples/radial_distance_example.py @@ -93,7 +93,7 @@ stellarator.export_invessel_build() # Construct magnets -stellarator.construct_magnets( +stellarator.construct_magnets_from_filaments( coils_file, width, thickness, toroidal_extent, sample_mod=6 ) # Export magnet files diff --git a/parastell/cubit_io.py b/parastell/cubit_io.py index 8b39178..bc08e95 100644 --- a/parastell/cubit_io.py +++ b/parastell/cubit_io.py @@ -69,6 +69,23 @@ def export_step_cubit(filename, export_dir=""): cubit.cmd(f'export step "{export_path}" overwrite') +def import_cub5_cubit(filename, import_dir): + """Imports cub5 file with Coreform Cubit with default import settings. + Arguments: + filename (str): name of cub5 input file. + import_dir (str): directory from which to import cub5 file. + Returns: + vol_id (int): Cubit volume ID of imported CAD solid. + """ + init_cubit() + import_path = Path(import_dir) / Path(filename).with_suffix(".cub5") + cubit.cmd( + f'import cubit "{import_path}" nofreesurfaces attributes_on separate_bodies' + ) + vol_id = cubit.get_last_id("volume") + return vol_id + + def export_cub5(filename, export_dir=""): """Export cub5 representation of model (native Cubit format). @@ -161,3 +178,21 @@ def export_dagmc_cubit( # exports if delete_upon_export: cubit.cmd(f"delete mesh volume all propagate") + + +def import_geom_to_cubit(filename, import_dir=""): + """Attempts to open a geometry file with the appropriate cubit_io function, + based on file extension + Arguments: + filename (path): name of the file to import, including the suffix + import_dir (str): directory from which to import the file. + Returns: + vol_id (int): Cubit volume ID of imported CAD solid. + """ + importers = { + ".step": import_step_cubit, + ".cub5": import_cub5_cubit, + } + filename = Path(filename) + vol_id = importers[filename.suffix](filename, import_dir) + return vol_id diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index ad8a418..d211954 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -18,10 +18,6 @@ class MagnetSet(object): Arguments: coils_file (str): path to coil filament data file. - width (float): width of coil cross-section in toroidal direction [cm]. - thickness (float): thickness of coil cross-section in radial direction - [cm]. - toroidal_extent (float): toroidal extent to model [deg]. logger (object): logger object (optional, defaults to None). If no logger is supplied, a default logger will be instantiated. @@ -39,18 +35,12 @@ class MagnetSet(object): def __init__( self, coils_file, - width, - thickness, - toroidal_extent, logger=None, **kwargs, ): self.logger = logger self.coils_file = coils_file - self.width = width - self.thickness = thickness - self.toroidal_extent = toroidal_extent self.start_line = 3 self.sample_mod = 1 @@ -65,6 +55,166 @@ def __init__( ): self.__setattr__(name, kwargs[name]) + @property + def logger(self): + return self._logger + + @logger.setter + def logger(self, logger_object): + self._logger = log.check_init(logger_object) + + def _instantiate_filaments(self): + """Extracts filament coordinate data from input data file and + instantiates MagnetCoil class objects. + (Internal function not intended to be called externally) + """ + with open(self.coils_file, "r") as file: + data = file.readlines()[self.start_line :] + + coords = [] + self.filaments = [] + + for line in data: + columns = line.strip().split() + + if columns[0] == "end": + break + + # Coil current + s = float(columns[3]) + + # s = 0 signals end of filament + if s != 0: + coords.append( + [float(ord) * self.scale for ord in columns[0:3]] + ) + + else: + coords.append(coords[0]) + self.filaments.append(Filament(np.array(coords))) + coords.clear() + + def _filter_filaments(self, tol=0): + """Filters list of Filament objects such that only those within the + toroidal extent of the model are included and filaments are sorted by + center-of-mass toroidal angle. + (Internal function not intended to be called externally) + """ + + # Compute lower and upper bounds of toroidal extent within tolerance + lower_bound = 2 * np.pi - tol + upper_bound = self._toroidal_extent + tol + + # Create filter determining whether each coil lies within model's + # toroidal extent + filtered_filaments = [ + filament + for filament in self.filaments + if filament.in_toroidal_extent(lower_bound, upper_bound) + ] + self.filaments = filtered_filaments + + # Sort coils by center-of-mass toroidal angle and overwrite stored list + self.filaments = self.sort_filaments_toroidally() + + def import_geom_cubit(self): + """Import STEP file for magnet set into Coreform Cubit.""" + first_vol_id = 1 + if cubit_io.initialized: + first_vol_id += cubit.get_last_id("volume") + + last_vol_id = cubit_io.import_geom_to_cubit( + self.geometry_file, self.working_dir + ) + self.volume_ids = list(range(first_vol_id, last_vol_id + 1)) + + def mesh_magnets(self, min_size=20.0, max_size=50.0, max_gradient=1.5): + """Creates tetrahedral mesh of magnet volumes via Coreform Cubit. + + Arguments: + min_size (float): minimum size of mesh elements (defaults to 20.0). + max_size (float): maximum size of mesh elements (defaults to 50.0). + max_gradient (float): maximum transition in mesh element size + (defaults to 1.5). + """ + self._logger.info("Generating tetrahedral mesh of magnet coils...") + + if not hasattr(self, "volume_ids"): + self.import_geom_cubit() + + volume_ids_str = " ".join(str(id) for id in self.volume_ids) + cubit.cmd(f"volume {volume_ids_str} scheme tetmesh") + cubit.cmd( + f"volume {volume_ids_str} sizing function type skeleton min_size " + f"{min_size} max_size {max_size} max_gradient {max_gradient} " + "min_num_layers_3d 1 min_num_layers_2d 1 min_num_layers_1d 1" + ) + cubit.cmd(f"mesh volume {volume_ids_str}") + + def export_mesh(self, mesh_filename="magnet_mesh", export_dir=""): + """Creates tetrahedral mesh of magnet volumes and exports H5M format + via Coreform Cubit and MOAB. + + Arguments: + mesh_filename (str): name of H5M output file, excluding '.h5m' + extension (optional, defaults to 'magnet_mesh'). + export_dir (str): directory to which to export the H5M output file + (optional, defaults to empty string). + """ + self._logger.info("Exporting mesh H5M file for magnet coils...") + + cubit_io.export_mesh_cubit( + filename=mesh_filename, export_dir=export_dir + ) + + def sort_filaments_toroidally(self): + """Reorders list of coils by toroidal angle on range [-pi, pi]. + + Returns: + (list of object): sorted list of Filament class objects. + """ + return sorted(self.filaments, key=lambda x: x.com_toroidal_angle) + + +class MagnetSetFromFilaments(MagnetSet): + """Inherits from MagnetSet. This subclass enables the construction of + CAD solids using the filament data and CADquery. + + Arguments: + coils_file (str): path to coil filament data file. + width (float): width of coil cross-section in toroidal direction [cm]. + thickness (float): thickness of coil cross-section in radial direction + [cm]. + toroidal_extent (float): toroidal extent to model [deg]. + logger (object): logger object (optional, defaults to None). If no + logger is supplied, a default logger will be instantiated. + + Optional attributes: + start_line (int): starting line index for data in filament data file + (defaults to 3). + sample_mod (int): sampling modifier for filament points (defaults to + 1). For a user-defined value n, every nth point will be sampled. + scale (float): a scaling factor between the units of the point-locus + data and [cm] (defaults to m2cm = 100). + mat_tag (str): DAGMC material tag to use for magnets in DAGMC + neutronics model (defaults to 'magnets'). + """ + + def __init__( + self, + coils_file, + width, + thickness, + toroidal_extent, + logger=None, + **kwargs, + ): + super().__init__(coils_file, logger, **kwargs) + + self.width = width + self.thickness = thickness + self.toroidal_extent = toroidal_extent + # Define maximum length of coil cross-section self.max_cs_len = max(self._width, self._thickness) @@ -104,52 +254,14 @@ def toroidal_extent(self, angle): self._logger.error(e.args[0]) raise e - @property - def logger(self): - return self._logger - - @logger.setter - def logger(self, logger_object): - self._logger = log.check_init(logger_object) - def _instantiate_coils(self): - """Extracts filament coordinate data from input data file and - instantiates MagnetCoil class objects. - (Internal function not intended to be called externally) - """ - with open(self.coils_file, "r") as file: - data = file.readlines()[self.start_line :] - - coords = [] self.magnet_coils = [] - - for line in data: - columns = line.strip().split() - - if columns[0] == "end": - break - - # Coil current - s = float(columns[3]) - - # s = 0 signals end of filament - if s != 0: - coords.append( - [float(ord) * self.scale for ord in columns[0:3]] - ) - - else: - coords.append(coords[0]) - self.magnet_coils.append( - MagnetCoil( - np.array(coords), - np.average(coords[:-1], axis=0), - self._width, - self._thickness, - self.sample_mod, - ) + for filament in self.filaments: + self.magnet_coils.append( + MagnetCoil( + filament, self.width, self.thickness, self.sample_mod ) - coords.clear() + ) def _compute_radial_distance_data(self): """Computes average and maximum radial distance of filament points. @@ -159,8 +271,8 @@ def _compute_radial_distance_data(self): self.average_radial_distance = 0 self.max_radial_distance = -1 - for coil in self.magnet_coils: - radii = np.linalg.norm(coil.coords[:-1, :2], axis=1) + for filament in self.filaments: + radii = np.linalg.norm(filament.coords[:-1, :2], axis=1) radii_count += len(radii) self.average_radial_distance += np.sum(radii) self.max_radial_distance = max( @@ -169,33 +281,6 @@ def _compute_radial_distance_data(self): self.average_radial_distance /= radii_count - def _filter_coils(self): - """Filters list of MagnetCoil objects such that only those within the - toroidal extent of the model are included and coils are sorted by - center-of-mass toroidal angle. - (Internal function not intended to be called externally) - """ - # Define tolerance of toroidal extent to account for dimensionality of - # coil cross-section - # Multiply by factor of 2 to be conservative - tol = 2 * np.arctan2(self.max_cs_len, self.average_radial_distance) - - # Compute lower and upper bounds of toroidal extent within tolerance - lower_bound = 2 * np.pi - tol - upper_bound = self._toroidal_extent + tol - - # Create filter determining whether each coil lies within model's - # toroidal extent - filtered_coils = [ - coil - for coil in self.magnet_coils - if coil.in_toroidal_extent(lower_bound, upper_bound) - ] - self.magnet_coils = filtered_coils - - # Sort coils by center-of-mass toroidal angle and overwrite stored list - self.magnet_coils = self.sort_coils_toroidally() - def _cut_magnets(self): """Cuts the magnets at the planes defining the toriodal extent. (Internal function not intended to be called externally) @@ -218,15 +303,43 @@ def _cut_magnets(self): cut_coil = coil.solid.intersect(toroidal_region) coil.solid = cut_coil + def export_step(self, step_filename="magnet_set.step", export_dir=""): + """Export CAD solids as a STEP file via CadQuery. + + Arguments: + step_filename (str): name of STEP output file (optional, defaults + to 'magnet_set.step'). + export_dir (str): directory to which to export the STEP output file + (optional, defaults to empty string). + """ + self._logger.info("Exporting STEP file for magnet coils...") + + self.working_dir = export_dir + self.geometry_file = Path(step_filename).with_suffix(".step") + + export_path = Path(self.working_dir) / Path( + self.geometry_file + ).with_suffix(".step") + + coil_set = cq.Compound.makeCompound( + [coil.solid for coil in self.magnet_coils] + ) + cq.exporters.export(coil_set, str(export_path)) + def populate_magnet_coils(self): """Populates MagnetCoil class objects representing each of the magnetic coils that lie within the specified toroidal extent. """ self._logger.info("Populating magnet coils...") - self._instantiate_coils() + self._instantiate_filaments() self._compute_radial_distance_data() - self._filter_coils() + # Define tolerance of toroidal extent to account for dimensionality of + # coil cross-section + # Multiply by factor of 2 to be conservative + tol = 2 * np.arctan2(self.max_cs_len, self.average_radial_distance) + self._filter_filaments(tol=tol) + self._instantiate_coils() def build_magnet_coils(self): """Builds each filament in self.filtered_filaments in cubit, then cuts @@ -246,29 +359,47 @@ def import_step_cubit(self): if cubit_io.initialized: first_vol_id += cubit.get_last_id("volume") - last_vol_id = cubit_io.import_step_cubit( - self.step_filename, self.export_dir - ) +class MagnetSetFromGeometry(MagnetSet): + """An object representing a set of modular stellarator magnet coils. - self.volume_ids = list(range(first_vol_id, last_vol_id + 1)) + Arguments: + coils_file (str): path to coil filament data file. + geometry_file (str): path to existing coil geometry. Can be of the + types supported by + logger (object): logger object (optional, defaults to None). If no + logger is supplied, a default logger will be instantiated. - def export_step(self, step_filename="magnet_set", export_dir=""): - """Export CAD solids as a STEP file via CadQuery. + Optional attributes: + start_line (int): starting line index for data in filament data file + (defaults to 3). + sample_mod (int): sampling modifier for filament points (defaults to + 1). For a user-defined value n, every nth point will be sampled. + scale (float): a scaling factor between the units of the point-locus + data and [cm] (defaults to m2cm = 100). + mat_tag (str): DAGMC material tag to use for magnets in DAGMC + neutronics model (defaults to 'magnets'). + """ - Arguments: - step_filename (str): name of STEP output file, excluding '.step' - extension (optional, defaults to 'magnet_set'). - export_dir (str): directory to which to export the STEP output file - (optional, defaults to empty string). - """ - self._logger.info("Exporting STEP file for magnet coils...") + def __init__( + self, + coils_file, + geometry_file, + working_dir=".", + logger=None, + **kwargs, + ): + super().__init__(coils_file, logger, **kwargs) + self.geometry_file = geometry_file + self.working_dir = Path(working_dir) - self.export_dir = export_dir - self.step_filename = step_filename + for name in kwargs.keys() & ( + "start_line", + "sample_mod", + "scale", + "mat_tag", + ): + self.__setattr__(name, kwargs[name]) - export_path = Path(self.export_dir) / Path( - self.step_filename - ).with_suffix(".step") coil_set = cq.Compound.makeCompound(self.coil_solids) cq.exporters.export(coil_set, str(export_path)) @@ -288,95 +419,127 @@ def extract_solids_and_mat_tag(self): def mesh_magnets(self, min_size=20.0, max_size=50.0, max_gradient=1.5): """Creates tetrahedral mesh of magnet volumes via Coreform Cubit. +class Filament(object): + """Object containing basic data defining a Filament. - Arguments: - min_size (float): minimum size of mesh elements (defaults to 20.0). - max_size (float): maximum size of mesh elements (defaults to 50.0). - max_gradient (float): maximum transition in mesh element size - (defaults to 1.5). - """ - self._logger.info("Generating tetrahedral mesh of magnet coils...") + Arguments: + coords (2-D array of float): set of Cartesian coordinates defining + magnet filament location. + """ - if not hasattr(self, "volume_ids"): - self.import_step_cubit() + def __init__(self, coords): + self.coords = coords - volume_ids_str = " ".join(str(id) for id in self.volume_ids) - cubit.cmd(f"volume {volume_ids_str} scheme tetmesh") - cubit.cmd( - f"volume {volume_ids_str} sizing function type skeleton min_size " - f"{min_size} max_size {max_size} max_gradient {max_gradient} " - "min_num_layers_3d 1 min_num_layers_2d 1 min_num_layers_1d 1" + @property + def coords(self): + return self._coords + + @coords.setter + def coords(self, data): + self._coords = data + + tangents = np.subtract( + np.append(data[1:], [data[1]], axis=0), + np.append([data[-2]], data[0:-1], axis=0), + ) + self.tangents = ( + tangents / np.linalg.norm(tangents, axis=1)[:, np.newaxis] ) - cubit.cmd(f"mesh volume {volume_ids_str}") - def export_mesh(self, mesh_filename="magnet_mesh", export_dir=""): - """Creates tetrahedral mesh of magnet volumes and exports H5M format - via Coreform Cubit and MOAB. + self.com = np.average(data[:-1], axis=0) + self.com_toroidal_angle = np.arctan2(self.com[1], self.com[0]) + + def get_ob_mp_index(self): + """Finds the index of the outboard midplane coordinate on a coil + filament. + + Returns: + outboard_index (int): index of the outboard midplane point. + """ + # Compute radial distance of coordinates from z-axis + radii = np.linalg.norm(self.coords[:, :2], axis=1) + # Determine whether adjacent points cross the midplane (if so, they will + # have opposite signs) + shifted_coords = np.append(self.coords[1:], [self.coords[1]], axis=0) + midplane_flags = -np.sign(self.coords[:, 2] * shifted_coords[:, 2]) + # Find index of outboard midplane point + outboard_index = np.argmax(midplane_flags * radii) + + return outboard_index + + def reorder_coords(self, index): + """Reorders coil filament coordinate loop about a given index. Arguments: - mesh_filename (str): name of H5M output file, excluding '.h5m' - extension (optional, defaults to 'magnet_mesh'). - export_dir (str): directory to which to export the H5M output file - (optional, defaults to empty string). + index (int): index about which to reorder coordinate loop. """ - self._logger.info("Exporting mesh H5M file for magnet coils...") + self.coords = reorder_loop(self.coords, index) - cubit_io.export_mesh_cubit( - filename=mesh_filename, export_dir=export_dir - ) + def orient_coords(self, positive=True): + """Orients coil filament coordinate loop such that they initially + progress positively or negatively. - def sort_coils_toroidally(self): - """Reorders list of coils by toroidal angle on range [-pi, pi]. + Arguments: + positive (bool): progress coordinates in positive direciton + (defaults to True). If negative, coordinates will progress in + negative direction. + """ + if positive == (self.coords[0, 2] > self.coords[1, 2]): + self.coords = np.flip(self.coords, axis=0) + + def in_toroidal_extent(self, lower_bound, upper_bound): + """Determines if the coil lies within a given toroidal angular extent, + based on filament coordinates. Arguments: - magnet_coils (list of object): list of MagnetCoil class objects. + lower_bound (float): lower bound of toroidal extent [rad]. + upper_bound (float): upper bound of toroidal extent [rad]. Returns: - (list of object): sorted list of MagnetCoil class objects. + in_toroidal_extent (bool): flag to indicate whether coil lies + within toroidal bounds. """ - return sorted(self.magnet_coils, key=lambda x: x.com_toroidal_angle()) + # Compute toroidal angle of each point in filament + toroidal_angles = np.arctan2(self.coords[:, 1], self.coords[:, 0]) + # Ensure angles are positive + toroidal_angles = (toroidal_angles + 2 * np.pi) % (2 * np.pi) + # Compute bounds of toroidal extent of filament + min_tor_ang = np.min(toroidal_angles) + max_tor_ang = np.max(toroidal_angles) + + # Determine if filament toroidal extent overlaps with that of model + if (min_tor_ang >= lower_bound or min_tor_ang <= upper_bound) or ( + max_tor_ang >= lower_bound or max_tor_ang <= upper_bound + ): + in_toroidal_extent = True + else: + in_toroidal_extent = False + + return in_toroidal_extent class MagnetCoil(object): """An object representing a single modular stellarator magnet coil. Arguments: - coords (2-D array of float): set of Cartesian coordinates defining - magnet filament location. - tangents (2-D array of float): set of tangent vectors at each filament - location. - center_of_mass (1-D array of float): Cartesian coordinates of filament - center of mass. + filament (Filament object): filament definining the location of the + coil width (float): width of coil cross-section in toroidal direction [cm]. thickness (float): thickness of coil cross-section in radial direction [cm]. + sample_mod (int): Length of stride when sampling from coordinate data. """ - def __init__(self, coords, center_of_mass, width, thickness, sample_mod): + def __init__(self, filament, width, thickness, sample_mod): + self.filament = filament self.sample_mod = sample_mod - self.coords = coords - self.center_of_mass = center_of_mass + self.coords = filament.coords + self.center_of_mass = filament.com + self.tangents = filament.tangents self.width = width self.thickness = thickness - @property - def coords(self): - return self._coords - - @coords.setter - def coords(self, data): - self._coords = data - - # Compute tangents - tangents = np.subtract( - np.append(data[1:], [data[1]], axis=0), - np.append([data[-2]], data[0:-1], axis=0), - ) - self.tangents = ( - tangents / np.linalg.norm(tangents, axis=1)[:, np.newaxis] - ) - def create_magnet(self): """Creates a single magnet coil CAD solid in CadQuery. @@ -384,8 +547,8 @@ def create_magnet(self): coil (object): cq.Solid object representing a single magnet coil. """ # Sample filament coordinates and tangents by modifier - coords = self._coords[0 : -1 : self.sample_mod] - coords = np.append(coords, [self._coords[0]], axis=0) + coords = self.coords[0 : -1 : self.sample_mod] + coords = np.append(coords, [self.coords[0]], axis=0) tangents = self.tangents[0 : -1 : self.sample_mod] tangents = np.append(tangents, [self.tangents[0]], axis=0) @@ -456,7 +619,7 @@ def in_toroidal_extent(self, lower_bound, upper_bound): within toroidal bounds. """ # Compute toroidal angle of each point in filament - toroidal_angles = np.arctan2(self._coords[:, 1], self._coords[:, 0]) + toroidal_angles = np.arctan2(self.coords[:, 1], self.coords[:, 0]) # Ensure angles are positive toroidal_angles = (toroidal_angles + 2 * np.pi) % (2 * np.pi) # Compute bounds of toroidal extent of filament @@ -473,53 +636,6 @@ def in_toroidal_extent(self, lower_bound, upper_bound): return in_toroidal_extent - def com_toroidal_angle(self): - """Computes the toroidal angle of the coil center of mass, based on - filament coordinates. - - Returns: - (float): toroidal angle of coil center of mass [rad]. - """ - return np.arctan2(self.center_of_mass[1], self.center_of_mass[0]) - - def get_ob_mp_index(self): - """Finds the index of the outboard midplane coordinate on a coil - filament. - - Returns: - outboard_index (int): index of the outboard midplane point. - """ - # Compute radial distance of coordinates from z-axis - radii = np.linalg.norm(self.coords[:, :2], axis=1) - # Determine whether adjacent points cross the midplane (if so, they will - # have opposite signs) - shifted_coords = np.append(self.coords[1:], [self.coords[1]], axis=0) - midplane_flags = -np.sign(self.coords[:, 2] * shifted_coords[:, 2]) - # Find index of outboard midplane point - outboard_index = np.argmax(midplane_flags * radii) - - return outboard_index - - def reorder_coords(self, index): - """Reorders coil filament coordinate loop about a given index. - - Arguments: - index (int): index about which to reorder coordinate loop. - """ - self.coords = reorder_loop(self.coords, index) - - def orient_coords(self, positive=True): - """Orients coil filament coordinate loop such that they initially - progress positively or negatively. - - Arguments: - positive (bool): progress coordinates in positive direciton - (defaults to True). If negative, coordinates will progress in - negative direction. - """ - if positive == (self.coords[0, 2] > self.coords[1, 2]): - self.coords = np.flip(self.coords, axis=0) - def parse_args(): """Parser for running as a script""" diff --git a/parastell/parastell.py b/parastell/parastell.py index 8343782..f11a699 100644 --- a/parastell/parastell.py +++ b/parastell/parastell.py @@ -193,7 +193,7 @@ def export_invessel_component_mesh( components, mesh_size, import_dir, export_dir ) - def construct_magnets( + def construct_magnets_from_filaments( self, coils_file, width, thickness, toroidal_extent, **kwargs ): """Constructs MagnetSet class object. @@ -216,7 +216,7 @@ def construct_magnets( mat_tag (str): DAGMC material tag to use for magnets in DAGMC neutronics model (defaults to 'magnets'). """ - self.magnet_set = mc.MagnetSet( + self.magnet_set = mc.MagnetSetFromFilaments( coils_file, width, thickness, @@ -228,6 +228,17 @@ def construct_magnets( self.magnet_set.populate_magnet_coils() self.magnet_set.build_magnet_coils() + def add_magnets_from_geometry( + self, coils_file, geometry_file, working_dir=".", **kwargs + ): + self.magnet_set = mc.MagnetSetFromGeometry( + coils_file, + geometry_file, + working_dir, + logger=self._logger, + **kwargs, + ) + def export_magnets( self, step_filename="magnet_set", @@ -356,7 +367,7 @@ def build_cubit_model(self, skip_imprint=False): self.invessel_build.import_step_cubit() if self.magnet_set: - self.magnet_set.import_step_cubit() + self.magnet_set.import_geom_cubit() if skip_imprint: self.invessel_build.merge_layer_surfaces() diff --git a/parastell/radial_distance_utils.py b/parastell/radial_distance_utils.py index 35c1ff8..2baf9e9 100644 --- a/parastell/radial_distance_utils.py +++ b/parastell/radial_distance_utils.py @@ -21,11 +21,11 @@ def reorder_filament(coil): coordinates defining a MagnetCoil filament. """ # Start the filament at the outboard midplane - outboard_index = coil.get_ob_mp_index() + outboard_index = coil.filament.get_ob_mp_index() if outboard_index != 0: - coil.reorder_coords(outboard_index) + coil.filament.reorder_coords(outboard_index) # Ensure points initially progress in positive z-direction - coil.orient_coords() + coil.filament.orient_coords() def reorder_coils(magnet_set): @@ -66,11 +66,11 @@ def build_line(point_1, point_2): return curve_id -def build_magnet_surface(magnet_coils, sample_mod=1): +def build_magnet_surface(filaments, sample_mod=1): """Builds a surface in Coreform Cubit spanning a list of coil filaments. Arguments: - magnet_coils (list of object): list of MagnetCoil class objects, + filaments (list of object): list of MagnetCoil class objects, ordered toroidally. Each MagnetCoil object must also have its filament coordinates ordered poloidally (see reorder_coils function). @@ -83,19 +83,19 @@ def build_magnet_surface(magnet_coils, sample_mod=1): [ build_line(coord, next_coord) for coord, next_coord in zip( - downsample_loop(coil.coords, sample_mod), - downsample_loop(next_coil.coords, sample_mod), + downsample_loop(filament.coords, sample_mod), + downsample_loop(next_filament.coords, sample_mod), ) ] - for coil, next_coil in zip(magnet_coils[:-1], magnet_coils[1:]) + for filament, next_filament in zip(filaments[:-1], filaments[1:]) ] surface_lines = np.array(surface_lines) surface_sections = np.reshape( surface_lines, ( - len(magnet_coils) - 1, - len(downsample_loop(magnet_coils[0].coords, sample_mod)), + len(filaments) - 1, + len(downsample_loop(filaments[0].coords, sample_mod)), ), ) @@ -225,13 +225,18 @@ def measure_fw_coils_separation( invessel_build.calculate_loci() surface = invessel_build.Surfaces["chamber"] - magnet_set = magnet_coils.MagnetSet( + magnet_set = magnet_coils.MagnetSetFromFilaments( coils_file, width, thickness, toroidal_angles[-1] - toroidal_angles[0] ) reordered_coils = reorder_coils(magnet_set) - build_magnet_surface(reordered_coils, sample_mod=sample_mod) + reordered_filaments = [coil.filament for coil in reordered_coils] + build_magnet_surface(reordered_filaments, sample_mod=sample_mod) radial_distance_matrix = measure_surface_coils_separation(surface) + import cubit + + cubit.cmd('save cub5 "magnet_surface_test.cub5" overwrite') + return radial_distance_matrix diff --git a/tests/test_magnet_coils.py b/tests/test_magnet_coils.py index df15427..54657d4 100644 --- a/tests/test_magnet_coils.py +++ b/tests/test_magnet_coils.py @@ -2,27 +2,34 @@ import pytest import numpy as np +import cadquery as cq import parastell.magnet_coils as magnet_coils from parastell.cubit_io import create_new_cubit_instance +files_to_remove = [ + "magnet_set.step", + "magnet_mesh.exo", + "magnet_mesh.h5m", + "stellarator.log", + "step_import.log", + "single_coil.step", +] + def remove_files(): + for file in files_to_remove: + if Path(file).exists(): + Path.unlink(file) + - if Path("magnet_set.step").exists(): - Path.unlink("magnet_set.step") - if Path("magnet_mesh.exo").exists(): - Path.unlink("magnet_mesh.exo") - if Path("magnet_mesh.h5m").exists(): - Path.unlink("magnet_mesh.h5m") - if Path("stellarator.log").exists(): - Path.unlink("stellarator.log") - if Path("step_import.log").exists(): - Path.unlink("step_import.log") +simple_filament_coords = np.array( + [[0, 0, 0], [200, 300, 0], [0, 0, 100], [0, 0, 0]] +) @pytest.fixture -def coil_set(): +def coil_set_from_filaments(): coils_file = Path("files_for_tests") / "coils.example" width = 40.0 @@ -30,14 +37,61 @@ def coil_set(): toroidal_extent = 90.0 sample_mod = 10 - coil_set_obj = magnet_coils.MagnetSet( + coil_set_obj = magnet_coils.MagnetSetFromFilaments( coils_file, width, thickness, toroidal_extent, sample_mod=sample_mod ) return coil_set_obj -def test_magnet_construction(coil_set): +@pytest.fixture +def coil_set_from_geometry(): + coils_file = Path("files_for_tests") / "coils.example" + geom_file = Path("files_for_tests") / "magnet_geom.step" + + coil_set_obj = magnet_coils.MagnetSetFromGeometry(coils_file, geom_file) + + return coil_set_obj + + +@pytest.fixture +def single_filament(): + return magnet_coils.Filament(simple_filament_coords) + + +@pytest.fixture +def single_coil(single_filament): + return magnet_coils.MagnetCoil(single_filament, 10, 20, 1) + + +def test_single_filament(single_filament): + tangents_exp = np.array( + [ + [0.53452248, 0.80178373, -0.26726124], + [0.0, 0.0, 1.0], + [-0.5547002, -0.83205029, 0.0], + [0.53452248, 0.80178373, -0.26726124], + ] + ) + com_exp = np.array([66.66666667, 100.0, 33.33333333]) + com_toroidal_angle_exp = 0.982793723247329 + + assert np.allclose(tangents_exp, single_filament.tangents) + assert np.allclose(com_exp, single_filament.com) + assert np.isclose( + com_toroidal_angle_exp, single_filament.com_toroidal_angle + ) + + +def test_single_coil(single_coil): + remove_files() + single_coil.create_magnet() + cq.exporters.export(single_coil.solid, "single_coil.step") + assert Path("single_coil.step").exists() + remove_files() + + +def test_magnet_construction(coil_set_from_filaments): width_exp = 40.0 thickness_exp = 50.0 @@ -50,39 +104,59 @@ def test_magnet_construction(coil_set): remove_files() - coil_set.populate_magnet_coils() - coil_set.build_magnet_coils() + coil_set_from_filaments.populate_magnet_coils() - assert coil_set.width == width_exp - assert coil_set.thickness == thickness_exp - assert coil_set.toroidal_extent == toroidal_extent_exp - assert coil_set.max_cs_len == max_cs_len_exp - assert coil_set.average_radial_distance == average_radial_distance_exp - assert coil_set.max_radial_distance == max_radial_distance_exp + assert len(coil_set_from_filaments.magnet_coils) == len_coils_exp + assert coil_set_from_filaments.width == width_exp + assert coil_set_from_filaments.thickness == thickness_exp + assert coil_set_from_filaments.toroidal_extent == toroidal_extent_exp + assert coil_set_from_filaments.max_cs_len == max_cs_len_exp + assert ( + coil_set_from_filaments.average_radial_distance + == average_radial_distance_exp + ) + assert ( + coil_set_from_filaments.max_radial_distance == max_radial_distance_exp + ) - test_coil = coil_set.magnet_coils[0] + test_coil = coil_set_from_filaments.magnet_coils[0] assert len(test_coil.coords) == len_coords_exp - assert len(coil_set.coil_solids) == len_coils_exp + assert len(coil_set_from_filaments.coil_solids) == len_coils_exp remove_files() -def test_magnet_exports(coil_set): +def test_magnet_exports_from_filaments(coil_set_from_filaments): volume_ids_exp = list(range(1, 2)) remove_files() create_new_cubit_instance() - coil_set.populate_magnet_coils() - coil_set.build_magnet_coils() - coil_set.export_step() + coil_set_from_filaments.populate_magnet_coils() + coil_set_from_filaments.build_magnet_coils() + coil_set_from_filaments.export_step() assert Path("magnet_set.step").exists() - coil_set.mesh_magnets() - assert coil_set.volume_ids == volume_ids_exp + coil_set_from_filaments.mesh_magnets() + assert coil_set_from_filaments.volume_ids == volume_ids_exp + + coil_set_from_filaments.export_mesh() + assert Path("magnet_mesh.h5m").exists() + + remove_files() + + +def test_magnet_exports_from_geometry(coil_set_from_geometry): + volume_ids_exp = list(range(1, 2)) + + remove_files() + create_new_cubit_instance() + + coil_set_from_geometry.mesh_magnets() + assert coil_set_from_geometry.volume_ids == volume_ids_exp - coil_set.export_mesh() + coil_set_from_geometry.export_mesh() assert Path("magnet_mesh.h5m").exists() remove_files() diff --git a/tests/test_parastell.py b/tests/test_parastell.py index 0171b16..79686ea 100644 --- a/tests/test_parastell.py +++ b/tests/test_parastell.py @@ -87,11 +87,11 @@ def test_parastell(stellarator): toroidal_extent = 90.0 sample_mod = 6 - stellarator.construct_magnets( + stellarator.construct_magnets_from_filaments( coils_file, width, thickness, toroidal_extent, sample_mod=sample_mod ) - step_filename_exp = "magnet_set" + step_filename_exp = "magnet_set.step" export_mesh = True mesh_filename_exp = "magnet_mesh" @@ -148,5 +148,48 @@ def test_parastell(stellarator): stellarator.export_cad_to_dagmc(min_mesh_size=50, max_mesh_size=100) assert Path(filename_exp).with_suffix(".h5m").exists() + # Test with custom magnet geometry + + create_new_cubit_instance() + + geometry_file = Path("files_for_tests") / "magnet_geom.step" + + stellarator.construct_invessel_build( + toroidal_angles, + poloidal_angles, + wall_s, + radial_build_dict, + num_ribs=num_ribs, + ) + + stellarator.export_invessel_build() + + stellarator.add_magnets_from_geometry(coils_file, geometry_file) + + stellarator.build_cubit_model() + + import cubit + + cubit.cmd('save cub5 "test.cub5"') + + assert ( + stellarator.invessel_build.radial_build.radial_build["chamber"][ + "vol_id" + ] + == chamber_volume_id_exp + ) + assert ( + stellarator.invessel_build.radial_build.radial_build[ + component_name_exp + ]["vol_id"] + == component_volume_id_exp + ) + assert stellarator.magnet_set.volume_ids == magnet_volume_ids_exp + + stellarator.export_dagmc(filename=filename_exp) + stellarator.export_cub5(filename=filename_exp) + + assert Path(filename_exp).with_suffix(".h5m").exists() + assert Path(filename_exp).with_suffix(".cub5").exists() remove_files() From 1e78df1f651b8a98a536036eef7be7725a64f1c4 Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 27 Dec 2024 13:13:29 -0600 Subject: [PATCH 02/15] add necessary test file --- tests/files_for_tests/magnet_geom.step | 1604 ++++++++++++++++++++++++ 1 file changed, 1604 insertions(+) create mode 100644 tests/files_for_tests/magnet_geom.step diff --git a/tests/files_for_tests/magnet_geom.step b/tests/files_for_tests/magnet_geom.step new file mode 100644 index 0000000..5825f3d --- /dev/null +++ b/tests/files_for_tests/magnet_geom.step @@ -0,0 +1,1604 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('Open CASCADE Model'),'2;1'); +FILE_NAME('Open CASCADE Shape Model','2024-11-06T16:49:05',('Author'),( + 'Open CASCADE'),'Open CASCADE STEP processor 7.7','Open CASCADE 7.7' + ,'Unknown'); +FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }')); +ENDSEC; +DATA; +#1 = APPLICATION_PROTOCOL_DEFINITION('international standard', + 'automotive_design',2000,#2); +#2 = APPLICATION_CONTEXT( + 'core data for automotive mechanical design processes'); +#3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10); +#4 = PRODUCT_DEFINITION_SHAPE('','',#5); +#5 = PRODUCT_DEFINITION('design','',#6,#9); +#6 = PRODUCT_DEFINITION_FORMATION('','',#7); +#7 = PRODUCT('Open CASCADE STEP translator 7.7 1', + 'Open CASCADE STEP translator 7.7 1','',(#8)); +#8 = PRODUCT_CONTEXT('',#2,'mechanical'); +#9 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design'); +#10 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#15),#725); +#11 = AXIS2_PLACEMENT_3D('',#12,#13,#14); +#12 = CARTESIAN_POINT('',(0.,0.,0.)); +#13 = DIRECTION('',(0.,0.,1.)); +#14 = DIRECTION('',(1.,0.,-0.)); +#15 = MANIFOLD_SOLID_BREP('',#16); +#16 = CLOSED_SHELL('',(#17,#451,#628,#699)); +#17 = ADVANCED_FACE('',(#18),#55,.F.); +#18 = FACE_BOUND('',#19,.F.); +#19 = EDGE_LOOP('',(#20,#277,#299,#450)); +#20 = ORIENTED_EDGE('',*,*,#21,.T.); +#21 = EDGE_CURVE('',#22,#22,#24,.T.); +#22 = VERTEX_POINT('',#23); +#23 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#24 = SURFACE_CURVE('',#25,(#54,#165),.PCURVE_S1.); +#25 = B_SPLINE_CURVE_WITH_KNOTS('',3,(#26,#27,#28,#29,#30,#31,#32,#33, + #34,#35,#36,#37,#38,#39,#40,#41,#42,#43,#44,#45,#46,#47,#48,#49,#50, + #51,#52,#53),.UNSPECIFIED.,.T.,.F.,(4,2,2,2,2,2,2,2,2,2,2,2,2,4),(0. + ,209.23228019313,482.64365057914,715.14729372521,912.73931944314, + 1.165060787701E+03,1.437843148576E+03,1.712941418707E+03, + 1.993387146468E+03,2.219646600857E+03,2.455042741061E+03, + 2.730847502047E+03,2.986740727954E+03,3.18959189978E+03), + .UNSPECIFIED.); +#26 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#27 = CARTESIAN_POINT('',(1.178068206983E+03,1.143011162431E+03, + 88.902052812263)); +#28 = CARTESIAN_POINT('',(1.059198871667E+03,1.133111066035E+03, + 103.20778721284)); +#29 = CARTESIAN_POINT('',(961.78978729139,1.051858369149E+03, + 122.65498397959)); +#30 = CARTESIAN_POINT('',(920.97596978499,940.83297255026,108.0665985826 + )); +#31 = CARTESIAN_POINT('',(919.03221624622,760.36472584502, + 156.98452136172)); +#32 = CARTESIAN_POINT('',(904.13905708826,686.9486858971,187.9725200736) + ); +#33 = CARTESIAN_POINT('',(868.30305523949,567.42888247732, + 206.00482966527)); +#34 = CARTESIAN_POINT('',(860.11758853447,491.71757644465, + 200.02847334382)); +#35 = CARTESIAN_POINT('',(837.5142328206,347.8525128263,156.15760998742) + ); +#36 = CARTESIAN_POINT('',(788.23979160928,269.71060622585, + 120.50734641085)); +#37 = CARTESIAN_POINT('',(657.15905341342,171.32200542051, + 90.463334707785)); +#38 = CARTESIAN_POINT('',(531.24614458489,157.45967248274, + 86.380602659075)); +#39 = CARTESIAN_POINT('',(393.81944439462,189.3940634281,13.515593340398 + )); +#40 = CARTESIAN_POINT('',(347.74739271531,237.2459665214,-92.79844272712 + )); +#41 = CARTESIAN_POINT('',(321.41946639248,345.9846568351,-234.53119284) + ); +#42 = CARTESIAN_POINT('',(316.74869984858,444.69048792449,-292.432677006 + )); +#43 = CARTESIAN_POINT('',(377.31916130385,598.25856806489, + -323.3518305216)); +#44 = CARTESIAN_POINT('',(445.28712272089,660.00237271927, + -315.8751767843)); +#45 = CARTESIAN_POINT('',(591.5528099863,705.09381005083,-329.8557821768 + )); +#46 = CARTESIAN_POINT('',(673.94738735828,716.95103012423, + -332.3985242526)); +#47 = CARTESIAN_POINT('',(828.95136848228,765.07732270351, + -302.3851476386)); +#48 = CARTESIAN_POINT('',(913.775332618,794.82059179459,-267.5279287865) + ); +#49 = CARTESIAN_POINT('',(1.060964764734E+03,830.02513487346, + -166.8253263552)); +#50 = CARTESIAN_POINT('',(1.12631110515E+03,852.50000157897, + -101.5153023671)); +#51 = CARTESIAN_POINT('',(1.216526794197E+03,933.9985011832, + -30.71410020296)); +#52 = CARTESIAN_POINT('',(1.235828801867E+03,1.016396857139E+03, + 8.919736019131)); +#53 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#54 = PCURVE('',#55,#160); +#55 = B_SPLINE_SURFACE_WITH_KNOTS('',3,1,( + (#56,#57) + ,(#58,#59) + ,(#60,#61) + ,(#62,#63) + ,(#64,#65) + ,(#66,#67) + ,(#68,#69) + ,(#70,#71) + ,(#72,#73) + ,(#74,#75) + ,(#76,#77) + ,(#78,#79) + ,(#80,#81) + ,(#82,#83) + ,(#84,#85) + ,(#86,#87) + ,(#88,#89) + ,(#90,#91) + ,(#92,#93) + ,(#94,#95) + ,(#96,#97) + ,(#98,#99) + ,(#100,#101) + ,(#102,#103) + ,(#104,#105) + ,(#106,#107) + ,(#108,#109) + ,(#110,#111) + ,(#112,#113) + ,(#114,#115) + ,(#116,#117) + ,(#118,#119) + ,(#120,#121) + ,(#122,#123) + ,(#124,#125) + ,(#126,#127) + ,(#128,#129) + ,(#130,#131) + ,(#132,#133) + ,(#134,#135) + ,(#136,#137) + ,(#138,#139) + ,(#140,#141) + ,(#142,#143) + ,(#144,#145) + ,(#146,#147) + ,(#148,#149) + ,(#150,#151) + ,(#152,#153) + ,(#154,#155) + ,(#156,#157) + ,(#158,#159 + )),.UNSPECIFIED.,.T.,.F.,.F.,(4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,4),(2,2),(0.,231.78584422142,281.97780706428, + 534.6687705374,562.21582109731,792.23444425384,806.32706316339, + 1.011125307796E+03,1.021482963204E+03,1.290645009447E+03, + 1.292851720834E+03,1.592831124065E+03,1.607089856103E+03, + 1.897582784408E+03,1.921345385356E+03,2.208258315485E+03, + 2.241884939283E+03,2.458906726906E+03,2.495960051918E+03, + 2.719676685698E+03,2.743967327556E+03,3.025210990951E+03, + 3.0394615204E+03,3.292831481351E+03,3.308687457118E+03, + 3.533404360598E+03),(0.,1.),.UNSPECIFIED.); +#56 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#57 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#58 = CARTESIAN_POINT('',(1.178068206983E+03,1.143011162431E+03, + 88.902052812263)); +#59 = CARTESIAN_POINT('',(1.214518599337E+03,1.183185736462E+03, + 96.55905917632)); +#60 = CARTESIAN_POINT('',(1.059198871667E+03,1.133111066035E+03, + 103.20778721284)); +#61 = CARTESIAN_POINT('',(1.105764206144E+03,1.18048705174E+03, + 125.20916979138)); +#62 = CARTESIAN_POINT('',(1.007826505234E+03,1.090259381874E+03, + 113.46400227535)); +#63 = CARTESIAN_POINT('',(1.022182824328E+03,1.143986300442E+03, + 142.98091296698)); +#64 = CARTESIAN_POINT('',(999.07677877083,1.080846908264E+03, + 114.5864633831)); +#65 = CARTESIAN_POINT('',(1.009183392587E+03,1.136208806935E+03, + 145.48583926152)); +#66 = CARTESIAN_POINT('',(949.35488717979,1.015432017596E+03, + 118.94657828131)); +#67 = CARTESIAN_POINT('',(948.61443848197,1.085685892157E+03, + 157.57810330425)); +#68 = CARTESIAN_POINT('',(920.80189350862,924.67082042352, + 112.44752943395)); +#69 = CARTESIAN_POINT('',(946.27205443502,976.10493793072, + 151.38643049645)); +#70 = CARTESIAN_POINT('',(919.82996917614,834.43228106456, + 136.90768783108)); +#71 = CARTESIAN_POINT('',(945.45260270986,873.72375324464, + 171.32618546094)); +#72 = CARTESIAN_POINT('',(919.57429082723,825.67086113344, + 139.40939693563)); +#73 = CARTESIAN_POINT('',(945.39110777202,863.86497509643, + 173.57349674222)); +#74 = CARTESIAN_POINT('',(915.79528621862,744.76152674923,163.369994476) + ); +#75 = CARTESIAN_POINT('',(944.42998573533,774.62937738797, + 197.76179666504)); +#76 = CARTESIAN_POINT('',(902.06714479911,680.03846888831, + 189.01508514552)); +#77 = CARTESIAN_POINT('',(928.03167174473,700.90468143827, + 229.03868470183)); +#78 = CARTESIAN_POINT('',(883.70666438192,618.80281488271, + 198.25389109635)); +#79 = CARTESIAN_POINT('',(907.69845073456,631.02907965246, + 242.01668863906)); +#80 = CARTESIAN_POINT('',(882.68102106784,615.18143536609, + 198.72813937179)); +#81 = CARTESIAN_POINT('',(906.51424332594,627.02472954887, + 242.69441236352)); +#82 = CARTESIAN_POINT('',(867.24184448253,557.73193360769, + 205.18020017959)); +#83 = CARTESIAN_POINT('',(888.0054401839,565.29439137085,252.00785279242 + )); +#84 = CARTESIAN_POINT('',(859.4784759225,487.64977440039,198.7880193854) + ); +#85 = CARTESIAN_POINT('',(876.50839717942,489.32731188382, + 247.46915120988)); +#86 = CARTESIAN_POINT('',(849.72096738999,425.54551857416, + 179.84966664931)); +#87 = CARTESIAN_POINT('',(865.55412109633,419.19585941328, + 227.90297525684)); +#88 = CARTESIAN_POINT('',(849.20098643529,422.55929391341, + 178.92280209409)); +#89 = CARTESIAN_POINT('',(865.0295168282,415.8432769491,226.92502661335) + ); +#90 = CARTESIAN_POINT('',(833.84365741078,342.10376619291, + 153.54468358374)); +#91 = CARTESIAN_POINT('',(850.92942441207,326.09949208154, + 199.55815084805)); +#92 = CARTESIAN_POINT('',(785.90581268231,267.95873234953,119.9723929832 + )); +#93 = CARTESIAN_POINT('',(814.74559997743,239.09814489192, + 150.42107423387)); +#94 = CARTESIAN_POINT('',(724.75597357367,222.05994361689, + 105.95670687167)); +#95 = CARTESIAN_POINT('',(746.99128745957,187.26592848495, + 134.22346744767)); +#96 = CARTESIAN_POINT('',(724.25563319256,221.68869105112, + 105.84334894335)); +#97 = CARTESIAN_POINT('',(746.43823924445,186.84683244536, + 134.09397491733)); +#98 = CARTESIAN_POINT('',(655.32316337656,171.12113339847, + 90.401989595809)); +#99 = CARTESIAN_POINT('',(670.41790396166,129.78631749731, + 116.66993631072)); +#100 = CARTESIAN_POINT('',(530.74648699776,157.57577991095, + 86.115679214855)); +#101 = CARTESIAN_POINT('',(536.89362797018,112.23272461948, + 107.59788978439)); +#102 = CARTESIAN_POINT('',(459.5946955201,174.1096057422,48.390288574738 + )); +#103 = CARTESIAN_POINT('',(452.11013556385,127.47583964633, + 68.463604521195)); +#104 = CARTESIAN_POINT('',(456.41634335042,174.92948909651, + 46.525835806506)); +#105 = CARTESIAN_POINT('',(448.3818501155,128.24004032485,66.62395590029 + )); +#106 = CARTESIAN_POINT('',(389.5805198092,193.88497849112,3.646235650355 + )); +#107 = CARTESIAN_POINT('',(371.49061944001,146.10756255496, + 25.855457261112)); +#108 = CARTESIAN_POINT('',(347.1374052923,239.76531546943, + -96.08222565542)); +#109 = CARTESIAN_POINT('',(318.66859061781,194.02035365751, + -78.91660384912)); +#110 = CARTESIAN_POINT('',(333.69357873396,295.29054274459, + -168.4552066031)); +#111 = CARTESIAN_POINT('',(297.74510023139,254.35152330045, + -164.3745612242)); +#112 = CARTESIAN_POINT('',(332.72744510444,299.7454302083, + -173.8478901057)); +#113 = CARTESIAN_POINT('',(296.3869917766,258.9660674834,-170.6640328428 + )); +#114 = CARTESIAN_POINT('',(320.92840968066,361.00384777106, + -243.1499764834)); +#115 = CARTESIAN_POINT('',(281.65302303526,319.81979536194, + -249.9823158014)); +#116 = CARTESIAN_POINT('',(319.31283723141,451.19150584044, + -293.7415816349)); +#117 = CARTESIAN_POINT('',(275.12439359132,416.49902694289, + -308.0024519443)); +#118 = CARTESIAN_POINT('',(353.90111545377,538.88533141732, + -311.3977172909)); +#119 = CARTESIAN_POINT('',(304.88072900251,517.36882112178, + -336.5872791122)); +#120 = CARTESIAN_POINT('',(358.26616840192,547.96205454181, + -312.8668949681)); +#121 = CARTESIAN_POINT('',(308.45789443601,527.86290731499, + -339.1404879232)); +#122 = CARTESIAN_POINT('',(395.62303511305,614.11194660346, + -321.6036103664)); +#123 = CARTESIAN_POINT('',(338.83015169465,604.86759119353, + -354.6444887552)); +#124 = CARTESIAN_POINT('',(454.9043393223,662.96721107469, + -316.7944252615)); +#125 = CARTESIAN_POINT('',(402.96773505925,656.56665818927, + -359.6102410339)); +#126 = CARTESIAN_POINT('',(527.56983812138,685.36885459427, + -323.7400574419)); +#127 = CARTESIAN_POINT('',(483.6171601418,690.87330211529,-366.649615046 + )); +#128 = CARTESIAN_POINT('',(538.32486432968,688.41101185876, + -324.6603913111)); +#129 = CARTESIAN_POINT('',(495.51723074804,695.22360485239, + -367.706731414)); +#130 = CARTESIAN_POINT('',(614.74555860104,708.67147780925, + -330.2480134527)); +#131 = CARTESIAN_POINT('',(579.08177904429,720.98525587998, + -375.6941343133)); +#132 = CARTESIAN_POINT('',(684.08930797469,720.09993659335, + -330.434747059)); +#133 = CARTESIAN_POINT('',(655.90689467962,733.46763016086, + -378.2563683958)); +#134 = CARTESIAN_POINT('',(751.9717477027,741.17636399642, + -317.2906896338)); +#135 = CARTESIAN_POINT('',(733.02072854281,754.94274655484, + -366.8910709321)); +#136 = CARTESIAN_POINT('',(758.62793299532,743.26453738585, + -315.8853482299)); +#137 = CARTESIAN_POINT('',(740.48787215445,757.12730949169, + -365.6268463667)); +#138 = CARTESIAN_POINT('',(842.38519210409,769.73405999669, + -296.732848228)); +#139 = CARTESIAN_POINT('',(833.13484918799,785.89273532765, + -347.6876386528)); +#140 = CARTESIAN_POINT('',(919.84538422725,796.2724174474, + -263.3749812199)); +#141 = CARTESIAN_POINT('',(920.57211116411,816.15302640666, + -312.2469113162)); +#142 = CARTESIAN_POINT('',(993.68719586923,813.93378893034, + -212.8546246041)); +#143 = CARTESIAN_POINT('',(1.002310650952E+03,836.63550307721, + -258.6924029856)); +#144 = CARTESIAN_POINT('',(997.23441785561,814.79950736035, + -210.3756575128)); +#145 = CARTESIAN_POINT('',(1.006227829523E+03,837.59565303316, + -256.069803756)); +#146 = CARTESIAN_POINT('',(1.063566741348E+03,831.36160235673, + -163.1237980721)); +#147 = CARTESIAN_POINT('',(1.079297572541E+03,855.07236232424, + -206.0776733766)); +#148 = CARTESIAN_POINT('',(1.121596528688E+03,852.16191318709, + -106.6448582035)); +#149 = CARTESIAN_POINT('',(1.153360683264E+03,858.80877830514, + -143.090843395)); +#150 = CARTESIAN_POINT('',(1.170957936369E+03,892.94715769432, + -66.52038693537)); +#151 = CARTESIAN_POINT('',(1.206780786179E+03,907.06710545621, + -101.166788433)); +#152 = CARTESIAN_POINT('',(1.173819727628E+03,895.41805154506, + -64.2305726249)); +#153 = CARTESIAN_POINT('',(1.209868664867E+03,910.06873239902, + -98.58160668438)); +#154 = CARTESIAN_POINT('',(1.216526794197E+03,933.9985011832, + -30.71410020296)); +#155 = CARTESIAN_POINT('',(1.255617456262E+03,957.80134484501, + -57.81664145477)); +#156 = CARTESIAN_POINT('',(1.235828801867E+03,1.016396857139E+03, + 8.919736019131)); +#157 = CARTESIAN_POINT('',(1.283766682134E+03,1.031390244851E+03, + 0.66977502507)); +#158 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#159 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#160 = DEFINITIONAL_REPRESENTATION('',(#161),#164); +#161 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#162,#163),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,3.18959189978E+03),.PIECEWISE_BEZIER_KNOTS.); +#162 = CARTESIAN_POINT('',(0.,0.)); +#163 = CARTESIAN_POINT('',(3.533404360598E+03,0.)); +#164 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#165 = PCURVE('',#166,#271); +#166 = B_SPLINE_SURFACE_WITH_KNOTS('',3,1,( + (#167,#168) + ,(#169,#170) + ,(#171,#172) + ,(#173,#174) + ,(#175,#176) + ,(#177,#178) + ,(#179,#180) + ,(#181,#182) + ,(#183,#184) + ,(#185,#186) + ,(#187,#188) + ,(#189,#190) + ,(#191,#192) + ,(#193,#194) + ,(#195,#196) + ,(#197,#198) + ,(#199,#200) + ,(#201,#202) + ,(#203,#204) + ,(#205,#206) + ,(#207,#208) + ,(#209,#210) + ,(#211,#212) + ,(#213,#214) + ,(#215,#216) + ,(#217,#218) + ,(#219,#220) + ,(#221,#222) + ,(#223,#224) + ,(#225,#226) + ,(#227,#228) + ,(#229,#230) + ,(#231,#232) + ,(#233,#234) + ,(#235,#236) + ,(#237,#238) + ,(#239,#240) + ,(#241,#242) + ,(#243,#244) + ,(#245,#246) + ,(#247,#248) + ,(#249,#250) + ,(#251,#252) + ,(#253,#254) + ,(#255,#256) + ,(#257,#258) + ,(#259,#260) + ,(#261,#262) + ,(#263,#264) + ,(#265,#266) + ,(#267,#268) + ,(#269,#270 + )),.UNSPECIFIED.,.T.,.F.,.F.,(4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,4),(2,2),(0.,209.23228019313,222.50673066079, + 482.64365057914,521.49891968826,715.14729372521,746.73554473208, + 912.73931944314,956.05226445931,1.165060787701E+03, + 1.183772437718E+03,1.437843148576E+03,1.452241892468E+03, + 1.712941418707E+03,1.744199379991E+03,1.993387146468E+03, + 2.014074791318E+03,2.219646600857E+03,2.265547928379E+03, + 2.455042741061E+03,2.497306330196E+03,2.730847502047E+03, + 2.769771749825E+03,2.986740727954E+03,3.009298678456E+03, + 3.18959189978E+03),(0.,1.),.UNSPECIFIED.); +#167 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#168 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#169 = CARTESIAN_POINT('',(1.168133054106E+03,1.157010515852E+03, + 52.606947252995)); +#170 = CARTESIAN_POINT('',(1.178068206983E+03,1.143011162431E+03, + 88.902052812263)); +#171 = CARTESIAN_POINT('',(1.056514096872E+03,1.156883580516E+03, + 72.630502068623)); +#172 = CARTESIAN_POINT('',(1.059198871667E+03,1.133111066035E+03, + 103.20778721284)); +#173 = CARTESIAN_POINT('',(1.001045524464E+03,1.122038149565E+03, + 83.270907413599)); +#174 = CARTESIAN_POINT('',(1.014291667615E+03,1.095652224673E+03, + 112.17326757893)); +#175 = CARTESIAN_POINT('',(997.97567466326,1.119827940679E+03, + 83.865376469529)); +#176 = CARTESIAN_POINT('',(1.011646431145E+03,1.09326426919E+03, + 112.64777948003)); +#177 = CARTESIAN_POINT('',(940.40372810783,1.071804946185E+03, + 95.359304167162)); +#178 = CARTESIAN_POINT('',(957.92039849994,1.041109347172E+03, + 121.33512179234)); +#179 = CARTESIAN_POINT('',(898.7874722016,986.179979794,117.20416374198) + ); +#180 = CARTESIAN_POINT('',(920.92496861013,936.09775667843, + 109.35013143998)); +#181 = CARTESIAN_POINT('',(886.51573507019,877.65017920072, + 146.2428155497)); +#182 = CARTESIAN_POINT('',(919.77622403852,829.44230133697, + 138.2602772613)); +#183 = CARTESIAN_POINT('',(885.61122164493,863.34993637576, + 150.09280998306)); +#184 = CARTESIAN_POINT('',(919.23595121287,815.84791125893, + 142.25484715074)); +#185 = CARTESIAN_POINT('',(884.68360838732,777.22546900741, + 173.43780347102)); +#186 = CARTESIAN_POINT('',(913.9293241041,736.07253113423, + 166.74856185688)); +#187 = CARTESIAN_POINT('',(873.00780785201,717.04003448039, + 196.18574463605)); +#188 = CARTESIAN_POINT('',(900.90159715451,676.15114836781, + 189.60157679881)); +#189 = CARTESIAN_POINT('',(855.3292493192,652.72991177983, + 210.15013524082)); +#190 = CARTESIAN_POINT('',(882.13465599279,613.55987136361, + 199.04490963891)); +#191 = CARTESIAN_POINT('',(852.75617061253,643.8409909714, + 211.82273745092)); +#192 = CARTESIAN_POINT('',(879.71425585336,604.25012889776, + 200.00482575879)); +#193 = CARTESIAN_POINT('',(836.27486303409,588.87273167202, + 220.11596284989)); +#194 = CARTESIAN_POINT('',(865.64139338044,543.54175642545, + 203.75432333532)); +#195 = CARTESIAN_POINT('',(827.20718595288,529.2664080136, + 216.45632823466)); +#196 = CARTESIAN_POINT('',(858.53061574203,481.61686641584, + 196.94831713125)); +#197 = CARTESIAN_POINT('',(816.63675068973,458.73557212563, + 201.38725924848)); +#198 = CARTESIAN_POINT('',(848.01468248774,414.6854149187, + 176.53793750867)); +#199 = CARTESIAN_POINT('',(814.49606006932,444.39080049406, + 197.70464317212)); +#200 = CARTESIAN_POINT('',(844.7602583283,400.91046643502, + 171.98901078877)); +#201 = CARTESIAN_POINT('',(801.87319047848,364.04919282658, + 173.20490985838)); +#202 = CARTESIAN_POINT('',(820.19350293907,321.93464428506, + 144.5434074757)); +#203 = CARTESIAN_POINT('',(768.81181456575,291.88403510254, + 154.58918956287)); +#204 = CARTESIAN_POINT('',(777.42765791082,261.59506826846, + 118.02918008495)); +#205 = CARTESIAN_POINT('',(715.93857892705,244.15146557236, + 140.62581363939)); +#206 = CARTESIAN_POINT('',(720.58227466146,218.92718435869, + 105.00008532155)); +#207 = CARTESIAN_POINT('',(711.47004397603,240.45656424658, + 139.52493406232)); +#208 = CARTESIAN_POINT('',(715.63926146923,215.59645490494, + 103.98371857214)); +#209 = CARTESIAN_POINT('',(644.59423506447,190.25988884564, + 124.19684228281)); +#210 = CARTESIAN_POINT('',(640.15543896383,169.56025801505, + 89.751728131046)); +#211 = CARTESIAN_POINT('',(528.93552797393,176.09299062159, + 119.5449094089)); +#212 = CARTESIAN_POINT('',(526.55263988445,158.55032090696, + 83.892059579301)); +#213 = CARTESIAN_POINT('',(456.24561722562,188.51834517559, + 87.370397058876)); +#214 = CARTESIAN_POINT('',(459.21156378098,174.19863559393, + 48.187148299211)); +#215 = CARTESIAN_POINT('',(452.49758608681,189.26801759873, + 85.561937730902)); +#216 = CARTESIAN_POINT('',(455.66270135681,175.12506078399, + 46.081177684064)); +#217 = CARTESIAN_POINT('',(384.11325904121,205.15875667189, + 49.303884379332)); +#218 = CARTESIAN_POINT('',(389.08708767557,194.41965651195, + 2.485540488728)); +#219 = CARTESIAN_POINT('',(335.84679578522,247.29300847123, + -43.95298755887)); +#220 = CARTESIAN_POINT('',(347.06501819636,240.0642861484, + -96.47191157505)); +#221 = CARTESIAN_POINT('',(314.20188066815,302.23257787823, + -124.5669780797)); +#222 = CARTESIAN_POINT('',(333.2287869526,297.21020967749, + -170.9573488757)); +#223 = CARTESIAN_POINT('',(312.30053110128,308.21412497455, + -132.8919535021)); +#224 = CARTESIAN_POINT('',(331.85451740724,303.87273371074, + -178.7624771788)); +#225 = CARTESIAN_POINT('',(299.16603581103,362.46176294952, + -203.5996923496)); +#226 = CARTESIAN_POINT('',(320.85276549027,367.81746902815, + -246.9316626596)); +#227 = CARTESIAN_POINT('',(296.03570825642,446.98596042264,-254.39910028 + )); +#228 = CARTESIAN_POINT('',(320.48521016234,454.16389627442, + -294.3400380072)); +#229 = CARTESIAN_POINT('',(323.53812605875,531.57173421972, + -276.700486818)); +#230 = CARTESIAN_POINT('',(352.74554373576,535.95553814951, + -310.8078373644)); +#231 = CARTESIAN_POINT('',(325.84296060535,538.01149896248, + -278.2018263885)); +#232 = CARTESIAN_POINT('',(355.56060551809,542.16828975663, + -311.8922706835)); +#233 = CARTESIAN_POINT('',(353.32607318483,607.69115359463, + -292.2310174582)); +#234 = CARTESIAN_POINT('',(389.77930755542,609.21801759018, + -322.1043883522)); +#235 = CARTESIAN_POINT('',(403.35824863543,666.88567611293, + -297.8572148184)); +#236 = CARTESIAN_POINT('',(451.84155989735,662.02300379626, + -316.5016736849)); +#237 = CARTESIAN_POINT('',(478.42466391225,707.30763150174, + -304.986991624)); +#238 = CARTESIAN_POINT('',(531.51543724609,686.58522146057, + -324.1171921304)); +#239 = CARTESIAN_POINT('',(492.6915127111,713.38204975598, + -306.2984681434)); +#240 = CARTESIAN_POINT('',(546.35541857437,690.64517663665, + -325.3328786582)); +#241 = CARTESIAN_POINT('',(567.96995695303,736.58922373106, + -313.4938551352)); +#242 = CARTESIAN_POINT('',(623.26707646564,710.10982025737, + -330.2252457877)); +#243 = CARTESIAN_POINT('',(632.62456916818,747.51497143365, + -316.3524014464)); +#244 = CARTESIAN_POINT('',(687.86537632957,721.27234628973, + -329.7035880215)); +#245 = CARTESIAN_POINT('',(705.83840218028,766.17130457839, + -308.3226198527)); +#246 = CARTESIAN_POINT('',(758.13809074948,743.09091630315,-316.09670239 + )); +#247 = CARTESIAN_POINT('',(718.95134039256,769.78879466426, + -306.3895192142)); +#248 = CARTESIAN_POINT('',(770.98113887103,747.15847686908, + -313.1770739649)); +#249 = CARTESIAN_POINT('',(802.32792156724,795.67590872918, + -290.245335604)); +#250 = CARTESIAN_POINT('',(854.74880142024,773.92326958905, + -291.2941880499)); +#251 = CARTESIAN_POINT('',(873.80840379858,820.33166554078, + -262.9067303473)); +#252 = CARTESIAN_POINT('',(925.47512053762,797.61892916098, + -259.5232841971)); +#253 = CARTESIAN_POINT('',(951.26524643061,841.25757664254, + -216.2773387751)); +#254 = CARTESIAN_POINT('',(1.000901455365E+03,815.65928447413, + -207.9188442602)); +#255 = CARTESIAN_POINT('',(962.18931639229,844.06038548822, + -209.2650636914)); +#256 = CARTESIAN_POINT('',(1.011549736015E+03,818.36451240634, + -200.1569232773)); +#257 = CARTESIAN_POINT('',(1.032894548979E+03,860.97155479361, + -160.8906605527)); +#258 = CARTESIAN_POINT('',(1.080496998393E+03,837.39434291726, + -147.5538751538)); +#259 = CARTESIAN_POINT('',(1.094595458635E+03,882.76217605053, + -117.5452577732)); +#260 = CARTESIAN_POINT('',(1.133965864208E+03,859.4151111864, + -95.50785344869)); +#261 = CARTESIAN_POINT('',(1.145717121408E+03,922.27490882705, + -78.42173217464)); +#262 = CARTESIAN_POINT('',(1.181070716101E+03,901.96840534044, + -58.54000254613)); +#263 = CARTESIAN_POINT('',(1.150365213162E+03,926.14744559752, + -74.82265625574)); +#264 = CARTESIAN_POINT('',(1.185252286197E+03,906.54926738957, + -54.95550978119)); +#265 = CARTESIAN_POINT('',(1.190493342512E+03,962.39815064055, + -43.33013174535)); +#266 = CARTESIAN_POINT('',(1.22028678567E+03,951.95066417113, + -21.9818587277)); +#267 = CARTESIAN_POINT('',(1.220653496216E+03,1.041882904981E+03, + -20.11921921824)); +#268 = CARTESIAN_POINT('',(1.233182779058E+03,1.022197080291E+03, + 12.583739739288)); +#269 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#270 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#271 = DEFINITIONAL_REPRESENTATION('',(#272),#276); +#272 = LINE('',#273,#274); +#273 = CARTESIAN_POINT('',(0.,1.)); +#274 = VECTOR('',#275,1.); +#275 = DIRECTION('',(1.,0.)); +#276 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#277 = ORIENTED_EDGE('',*,*,#278,.T.); +#278 = EDGE_CURVE('',#22,#279,#281,.T.); +#279 = VERTEX_POINT('',#280); +#280 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#281 = SEAM_CURVE('',#282,(#285,#292),.PCURVE_S1.); +#282 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#283,#284),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,1.),.PIECEWISE_BEZIER_KNOTS.); +#283 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#284 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#285 = PCURVE('',#55,#286); +#286 = DEFINITIONAL_REPRESENTATION('',(#287),#291); +#287 = LINE('',#288,#289); +#288 = CARTESIAN_POINT('',(3.533404360598E+03,0.)); +#289 = VECTOR('',#290,1.); +#290 = DIRECTION('',(0.,1.)); +#291 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#292 = PCURVE('',#55,#293); +#293 = DEFINITIONAL_REPRESENTATION('',(#294),#298); +#294 = LINE('',#295,#296); +#295 = CARTESIAN_POINT('',(0.,0.)); +#296 = VECTOR('',#297,1.); +#297 = DIRECTION('',(0.,1.)); +#298 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#299 = ORIENTED_EDGE('',*,*,#300,.F.); +#300 = EDGE_CURVE('',#279,#279,#301,.T.); +#301 = SURFACE_CURVE('',#302,(#331,#338),.PCURVE_S1.); +#302 = B_SPLINE_CURVE_WITH_KNOTS('',3,(#303,#304,#305,#306,#307,#308, + #309,#310,#311,#312,#313,#314,#315,#316,#317,#318,#319,#320,#321, + #322,#323,#324,#325,#326,#327,#328,#329,#330),.UNSPECIFIED.,.T.,.F., + (4,2,2,2,2,2,2,2,2,2,2,2,2,4),(0.,281.97780706428,562.21582109731, + 806.32706316339,1.021482963204E+03,1.292851720834E+03, + 1.607089856103E+03,1.921345385356E+03,2.241884939283E+03, + 2.495960051918E+03,2.743967327556E+03,3.0394615204E+03, + 3.292831481351E+03,3.533404360598E+03),.UNSPECIFIED.); +#303 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#304 = CARTESIAN_POINT('',(1.20541876021E+03,1.20313306927E+03, + 109.15979878623)); +#305 = CARTESIAN_POINT('',(1.055534721569E+03,1.174872248935E+03, + 136.23204716506)); +#306 = CARTESIAN_POINT('',(943.10572242002,1.081090858344E+03, + 158.67788866693)); +#307 = CARTESIAN_POINT('',(946.33403952981,951.41169215577, + 149.84298667821)); +#308 = CARTESIAN_POINT('',(944.37739826747,769.74688177617, + 199.08525133182)); +#309 = CARTESIAN_POINT('',(925.96397889784,691.89325427802, + 232.90750435998)); +#310 = CARTESIAN_POINT('',(887.12962562564,562.37338516382, + 252.44855372011)); +#311 = CARTESIAN_POINT('',(875.36035990985,481.5966728602, + 246.97616463591)); +#312 = CARTESIAN_POINT('',(850.81810905824,325.39099593332, + 199.34209882732)); +#313 = CARTESIAN_POINT('',(814.150778011,237.67155343728,149.61384713614 + )); +#314 = CARTESIAN_POINT('',(666.83086426075,127.09390195203, + 115.84777842363)); +#315 = CARTESIAN_POINT('',(524.06900294613,110.65231447035, + 106.75404043752)); +#316 = CARTESIAN_POINT('',(365.49512911538,147.50075857634, + 22.676588396699)); +#317 = CARTESIAN_POINT('',(310.16378877887,202.06561720196, + -96.49855156124)); +#318 = CARTESIAN_POINT('',(280.05826073711,326.40642742467, + -258.5674980722)); +#319 = CARTESIAN_POINT('',(273.69129338207,439.71696870758, + -321.3933245472)); +#320 = CARTESIAN_POINT('',(343.32007889251,616.25118450252, + -356.9364433642)); +#321 = CARTESIAN_POINT('',(425.9719206318,673.78386699289, + -361.0593381954)); +#322 = CARTESIAN_POINT('',(586.86579114506,723.38494578943, + -376.438158449)); +#323 = CARTESIAN_POINT('',(672.65041666914,736.06484898683, + -378.7621935059)); +#324 = CARTESIAN_POINT('',(837.45602835475,787.23439333772, + -346.8509299643)); +#325 = CARTESIAN_POINT('',(929.43848436236,819.22929499476, + -308.6067745529)); +#326 = CARTESIAN_POINT('',(1.079297572541E+03,855.07236232424, + -206.0776733766)); +#327 = CARTESIAN_POINT('',(1.153360683264E+03,858.80877830514, + -143.090843395)); +#328 = CARTESIAN_POINT('',(1.251369358353E+03,947.3472581661, + -66.17371188483)); +#329 = CARTESIAN_POINT('',(1.285687682208E+03,1.027179310211E+03, + -1.99027438737)); +#330 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#331 = PCURVE('',#55,#332); +#332 = DEFINITIONAL_REPRESENTATION('',(#333),#337); +#333 = LINE('',#334,#335); +#334 = CARTESIAN_POINT('',(0.,1.)); +#335 = VECTOR('',#336,1.); +#336 = DIRECTION('',(1.,0.)); +#337 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#338 = PCURVE('',#339,#444); +#339 = B_SPLINE_SURFACE_WITH_KNOTS('',3,1,( + (#340,#341) + ,(#342,#343) + ,(#344,#345) + ,(#346,#347) + ,(#348,#349) + ,(#350,#351) + ,(#352,#353) + ,(#354,#355) + ,(#356,#357) + ,(#358,#359) + ,(#360,#361) + ,(#362,#363) + ,(#364,#365) + ,(#366,#367) + ,(#368,#369) + ,(#370,#371) + ,(#372,#373) + ,(#374,#375) + ,(#376,#377) + ,(#378,#379) + ,(#380,#381) + ,(#382,#383) + ,(#384,#385) + ,(#386,#387) + ,(#388,#389) + ,(#390,#391) + ,(#392,#393) + ,(#394,#395) + ,(#396,#397) + ,(#398,#399) + ,(#400,#401) + ,(#402,#403) + ,(#404,#405) + ,(#406,#407) + ,(#408,#409) + ,(#410,#411) + ,(#412,#413) + ,(#414,#415) + ,(#416,#417) + ,(#418,#419) + ,(#420,#421) + ,(#422,#423) + ,(#424,#425) + ,(#426,#427) + ,(#428,#429) + ,(#430,#431) + ,(#432,#433) + ,(#434,#435) + ,(#436,#437) + ,(#438,#439) + ,(#440,#441) + ,(#442,#443 + )),.UNSPECIFIED.,.T.,.F.,.F.,(4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,4),(2,2),(0.,281.97780706428,295.56243148447, + 562.21582109731,600.79758735235,806.32706316339,837.67840191166, + 1.021482963204E+03,1.064606658661E+03,1.292851720834E+03, + 1.311466182752E+03,1.607089856103E+03,1.621478758028E+03, + 1.921345385356E+03,1.952709985806E+03,2.241884939283E+03, + 2.262789636712E+03,2.495960051918E+03,2.542331942498E+03, + 2.743967327556E+03,2.786729429334E+03,3.0394615204E+03, + 3.078929010456E+03,3.292831481351E+03,3.316053394305E+03, + 3.533404360598E+03),(0.,1.),.UNSPECIFIED.); +#340 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#341 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#342 = CARTESIAN_POINT('',(1.20541876021E+03,1.20313306927E+03, + 109.15979878623)); +#343 = CARTESIAN_POINT('',(1.19657387931E+03,1.214742488355E+03, + 71.354970571472)); +#344 = CARTESIAN_POINT('',(1.055534721569E+03,1.174872248935E+03, + 136.23204716506)); +#345 = CARTESIAN_POINT('',(1.05358925665E+03,1.200968112242E+03, + 104.71439401134)); +#346 = CARTESIAN_POINT('',(996.42968199018,1.125570442065E+03, + 148.03204859167)); +#347 = CARTESIAN_POINT('',(983.27229389294,1.152151774028E+03, + 119.08855493597)); +#348 = CARTESIAN_POINT('',(993.85237263366,1.123109553168E+03, + 148.52734823849)); +#349 = CARTESIAN_POINT('',(980.21654841404,1.149831957067E+03, + 119.70362216435)); +#350 = CARTESIAN_POINT('',(943.40866637867,1.068594961368E+03, + 157.90394249051)); +#351 = CARTESIAN_POINT('',(921.20574503279,1.100608756265E+03, + 131.48480984384)); +#352 = CARTESIAN_POINT('',(946.2833476744,946.70519512032,151.118734976) + ); +#353 = CARTESIAN_POINT('',(913.29053670633,1.000594353231E+03, + 157.76229652863)); +#354 = CARTESIAN_POINT('',(945.14434405469,840.95414070966, + 179.7837328796)); +#355 = CARTESIAN_POINT('',(911.11814684147,888.12944335332, + 188.03341457832)); +#356 = CARTESIAN_POINT('',(944.56316511354,827.75507130136, + 183.67920916074)); +#357 = CARTESIAN_POINT('',(910.96953005192,873.95081462557,191.863191732 + )); +#358 = CARTESIAN_POINT('',(938.50126507264,745.3624474608, + 209.19104182813)); +#359 = CARTESIAN_POINT('',(910.01715985116,785.5277831474, + 215.83123655271)); +#360 = CARTESIAN_POINT('',(922.70161195877,681.01264720341, + 234.54909403551)); +#361 = CARTESIAN_POINT('',(895.4742951886,721.79791120067, + 240.88205999854)); +#362 = CARTESIAN_POINT('',(902.67162855129,614.20888685464,244.627976815 + )); +#363 = CARTESIAN_POINT('',(875.96697851316,653.54101705844, + 255.70864473738)); +#364 = CARTESIAN_POINT('',(900.15703951155,604.94059216676, + 245.65135471378)); +#365 = CARTESIAN_POINT('',(873.32973171844,644.61203614679, + 257.38739364418)); +#366 = CARTESIAN_POINT('',(883.71916773225,539.08108245779, + 250.52266232655)); +#367 = CARTESIAN_POINT('',(855.12720640392,583.90319210451, + 266.54671820296)); +#368 = CARTESIAN_POINT('',(873.7788729123,471.53087863061, + 243.90665580511)); +#369 = CARTESIAN_POINT('',(843.35689597888,518.53405034204, + 263.03804812969)); +#370 = CARTESIAN_POINT('',(862.33170345305,398.6723268584, + 221.68883940999)); +#371 = CARTESIAN_POINT('',(831.05062152438,442.58645696264, + 246.53157275787)); +#372 = CARTESIAN_POINT('',(859.57609898733,384.81188391715, + 216.88189340098)); +#373 = CARTESIAN_POINT('',(828.811257913,428.36610869162,242.85200657582 + )); +#374 = CARTESIAN_POINT('',(838.36636433618,298.43286673825, + 184.39793728455)); +#375 = CARTESIAN_POINT('',(815.18311497827,341.6261717051,216.401137773) + ); +#376 = CARTESIAN_POINT('',(803.30223921768,229.52868998267, + 147.12733667737)); +#377 = CARTESIAN_POINT('',(792.35340946456,260.17048074804, + 185.46429835277)); +#378 = CARTESIAN_POINT('',(741.20029977916,182.91525910983, + 132.89342694391)); +#379 = CARTESIAN_POINT('',(736.51723401698,208.16467733345, + 168.59457361297)); +#380 = CARTESIAN_POINT('',(736.29394114698,179.55088697101, + 131.85178733893)); +#381 = CARTESIAN_POINT('',(732.11537471863,204.46513447452, + 167.42453419775)); +#382 = CARTESIAN_POINT('',(650.14009341408,125.26835014485, + 114.65481069238)); +#383 = CARTESIAN_POINT('',(654.41297809965,146.14207200336, + 149.61496319969)); +#384 = CARTESIAN_POINT('',(519.37242841843,111.74367624259, + 104.26386970466)); +#385 = CARTESIAN_POINT('',(521.53715648821,129.33451084384, + 140.30188099372)); +#386 = CARTESIAN_POINT('',(441.15382770255,129.91964474799, + 62.791586209786)); +#387 = CARTESIAN_POINT('',(438.22066443735,144.21553037801, + 102.02857842753)); +#388 = CARTESIAN_POINT('',(437.57362193708,130.83902970584, + 60.704982516957)); +#389 = CARTESIAN_POINT('',(434.48018914869,144.97965298572, + 100.18776385665)); +#390 = CARTESIAN_POINT('',(360.51294275406,152.51216468147, + 11.844823082628)); +#391 = CARTESIAN_POINT('',(355.83711603569,163.25425783658, + 58.49042085639)); +#392 = CARTESIAN_POINT('',(309.48138669058,204.88405069493, + -100.1721688249)); +#393 = CARTESIAN_POINT('',(298.6860164447,212.05526932838, + -47.88373788942)); +#394 = CARTESIAN_POINT('',(293.77255201241,269.76413613401, + -184.738507727)); +#395 = CARTESIAN_POINT('',(274.73760607337,274.69381971984, + -138.3056147614)); +#396 = CARTESIAN_POINT('',(292.36965639872,276.39144207075, + -192.5641556371)); +#397 = CARTESIAN_POINT('',(272.85795961445,280.71161910873, + -146.5995570419)); +#398 = CARTESIAN_POINT('',(279.24509966947,348.43913660386, + -270.4507450043)); +#399 = CARTESIAN_POINT('',(257.81975263328,342.82190123836, + -227.5556644874)); +#400 = CARTESIAN_POINT('',(277.49189083365,449.3528611872, + -323.3333998452)); +#401 = CARTESIAN_POINT('',(253.22477282045,441.96553965547, + -283.7246444454)); +#402 = CARTESIAN_POINT('',(315.06571336287,544.61612401723, + -342.5135539837)); +#403 = CARTESIAN_POINT('',(285.68296626613,539.83682677471, + -308.3638804238)); +#404 = CARTESIAN_POINT('',(317.94993608573,550.8995605323, + -343.7281454827)); +#405 = CARTESIAN_POINT('',(288.05340921329,546.39390226629, + -309.8515341718)); +#406 = CARTESIAN_POINT('',(356.91252901125,625.49893495088, + -357.6396603773)); +#407 = CARTESIAN_POINT('',(319.19708810077,625.35441965958, + -325.7493194195)); +#408 = CARTESIAN_POINT('',(432.67089625785,675.84905702669, + -361.6996506057)); +#409 = CARTESIAN_POINT('',(381.58462371148,684.10295454626, + -339.6895003333)); +#410 = CARTESIAN_POINT('',(522.2511018189,703.46524166113, + -370.2620518657)); +#411 = CARTESIAN_POINT('',(468.11031232786,724.39485023599, + -350.7415853765)); +#412 = CARTESIAN_POINT('',(537.33171859344,707.63308593782, + -371.4980975912)); +#413 = CARTESIAN_POINT('',(482.85063554467,730.08433110206, + -352.3882199262)); +#414 = CARTESIAN_POINT('',(618.57551864137,728.4996829922, + -376.7169121871)); +#415 = CARTESIAN_POINT('',(562.74444065305,754.71434907536, + -360.0247598653)); +#416 = CARTESIAN_POINT('',(686.71173616016,740.43066701917, + -376.0395042271)); +#417 = CARTESIAN_POINT('',(631.18423042149,766.49205509095, + -362.8152931557)); +#418 = CARTESIAN_POINT('',(760.82023383333,763.44018726353, + -361.6898969793)); +#419 = CARTESIAN_POINT('',(708.09678243875,786.36001490233, + -354.0301233284)); +#420 = CARTESIAN_POINT('',(773.83680016724,767.55357875211, + -358.7415801131)); +#421 = CARTESIAN_POINT('',(721.32994312394,790.04382113036, + -352.0414882353)); +#422 = CARTESIAN_POINT('',(863.84160654731,796.2286828154, + -335.4269420855)); +#423 = CARTESIAN_POINT('',(810.66618573987,817.78131612173, + -334.7433370816)); +#424 = CARTESIAN_POINT('',(941.11403201232,822.02183461057, + -300.6187144303)); +#425 = CARTESIAN_POINT('',(888.95640775797,844.61106616961, + -304.294764537)); +#426 = CARTESIAN_POINT('',(1.02089472545E+03,841.1036587512, + -246.0351527066)); +#427 = CARTESIAN_POINT('',(971.25803668978,866.71214696489, + -254.415372144)); +#428 = CARTESIAN_POINT('',(1.03178924243E+03,843.37022825881, + -238.282633211)); +#429 = CARTESIAN_POINT('',(982.2012717797,869.50922888726, + -247.3685882134)); +#430 = CARTESIAN_POINT('',(1.101793995178E+03,857.24773921553, + -187.0257167728)); +#431 = CARTESIAN_POINT('',(1.051121618559E+03,885.99349193742, + -200.2153505022)); +#432 = CARTESIAN_POINT('',(1.161191865528E+03,865.88326403328, + -136.9449376829)); +#433 = CARTESIAN_POINT('',(1.119488899486E+03,892.35391702974, + -159.0650225159)); +#434 = CARTESIAN_POINT('',(1.208242343439E+03,908.38743815096, + -100.0197594386)); +#435 = CARTESIAN_POINT('',(1.172264579591E+03,928.41200043742, + -120.2994628652)); +#436 = CARTESIAN_POINT('',(1.212725052321E+03,912.89197521696, + -96.15464940695)); +#437 = CARTESIAN_POINT('',(1.177188297478E+03,932.25161373475, + -116.5759494403)); +#438 = CARTESIAN_POINT('',(1.257403351872E+03,962.61070236438, + -54.00475396164)); +#439 = CARTESIAN_POINT('',(1.22525177331E+03,975.67090374394, + -78.85577121994)); +#440 = CARTESIAN_POINT('',(1.282874276262E+03,1.033346446129E+03, + 1.905508301433)); +#441 = CARTESIAN_POINT('',(1.27107271388E+03,1.051437068749E+03, + -31.8051405617)); +#442 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#443 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#444 = DEFINITIONAL_REPRESENTATION('',(#445),#449); +#445 = LINE('',#446,#447); +#446 = CARTESIAN_POINT('',(0.,0.)); +#447 = VECTOR('',#448,1.); +#448 = DIRECTION('',(1.,0.)); +#449 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#450 = ORIENTED_EDGE('',*,*,#278,.F.); +#451 = ADVANCED_FACE('',(#452),#339,.F.); +#452 = FACE_BOUND('',#453,.F.); +#453 = EDGE_LOOP('',(#454,#455,#477,#627)); +#454 = ORIENTED_EDGE('',*,*,#300,.T.); +#455 = ORIENTED_EDGE('',*,*,#456,.T.); +#456 = EDGE_CURVE('',#279,#457,#459,.T.); +#457 = VERTEX_POINT('',#458); +#458 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#459 = SEAM_CURVE('',#460,(#463,#470),.PCURVE_S1.); +#460 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#461,#462),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,1.),.PIECEWISE_BEZIER_KNOTS.); +#461 = CARTESIAN_POINT('',(1.256541540361E+03,1.091069207975E+03, + 38.369004377271)); +#462 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#463 = PCURVE('',#339,#464); +#464 = DEFINITIONAL_REPRESENTATION('',(#465),#469); +#465 = LINE('',#466,#467); +#466 = CARTESIAN_POINT('',(3.533404360598E+03,0.)); +#467 = VECTOR('',#468,1.); +#468 = DIRECTION('',(0.,1.)); +#469 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#470 = PCURVE('',#339,#471); +#471 = DEFINITIONAL_REPRESENTATION('',(#472),#476); +#472 = LINE('',#473,#474); +#473 = CARTESIAN_POINT('',(0.,0.)); +#474 = VECTOR('',#475,1.); +#475 = DIRECTION('',(0.,1.)); +#476 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#477 = ORIENTED_EDGE('',*,*,#478,.F.); +#478 = EDGE_CURVE('',#457,#457,#479,.T.); +#479 = SURFACE_CURVE('',#480,(#509,#515),.PCURVE_S1.); +#480 = B_SPLINE_CURVE_WITH_KNOTS('',3,(#481,#482,#483,#484,#485,#486, + #487,#488,#489,#490,#491,#492,#493,#494,#495,#496,#497,#498,#499, + #500,#501,#502,#503,#504,#505,#506,#507,#508),.UNSPECIFIED.,.T.,.F., + (4,2,2,2,2,2,2,2,2,2,2,2,2,4),(0.,294.89464339225,599.44015679986, + 835.7857673874,1.062201306783E+03,1.308503081198E+03, + 1.617815220003E+03,1.948298070295E+03,2.257677133181E+03, + 2.53658784644E+03,2.780433146279E+03,3.071972537268E+03, + 3.30856116683E+03,3.525421054515E+03),.UNSPECIFIED.); +#481 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#482 = CARTESIAN_POINT('',(1.194223616049E+03,1.219894390801E+03, + 74.60942979372)); +#483 = CARTESIAN_POINT('',(1.039593706748E+03,1.19936074875E+03, + 107.84929370025)); +#484 = CARTESIAN_POINT('',(913.08143316727,1.093831952504E+03, + 133.10678475979)); +#485 = CARTESIAN_POINT('',(912.00984568855,970.53916043029, + 165.68184776873)); +#486 = CARTESIAN_POINT('',(909.89484643157,774.1715654265, + 218.90946550254)); +#487 = CARTESIAN_POINT('',(890.71784650228,702.60466795808, + 248.63787213448)); +#488 = CARTESIAN_POINT('',(851.47887438954,571.73531894139, + 268.38252155664)); +#489 = CARTESIAN_POINT('',(838.04192564068,487.11714622309, + 260.76781375489)); +#490 = CARTESIAN_POINT('',(814.2482964314,335.67627066303, + 214.58674803142)); +#491 = CARTESIAN_POINT('',(788.55406358799,246.82775544822, + 180.36041365827)); +#492 = CARTESIAN_POINT('',(650.85500076073,143.47147053367, + 148.79946647393)); +#493 = CARTESIAN_POINT('',(508.46060315271,127.78852884585, + 139.41291841787)); +#494 = CARTESIAN_POINT('',(347.98806220289,165.07817380997, + 54.328774103047)); +#495 = CARTESIAN_POINT('',(286.92629019415,222.60708693331, + -70.86464506636)); +#496 = CARTESIAN_POINT('',(256.83900263544,346.87256094405, + -232.8353964596)); +#497 = CARTESIAN_POINT('',(252.60730904242,456.52518703908, + -291.7575096856)); +#498 = CARTESIAN_POINT('',(324.88119960101,639.76570313709, + -328.6508643616)); +#499 = CARTESIAN_POINT('',(407.73642100612,706.92778659119, + -345.2085306056)); +#500 = CARTESIAN_POINT('',(576.51995194256,758.96112503242, + -361.341473245)); +#501 = CARTESIAN_POINT('',(660.36986974258,771.11667935032, + -363.8451698411)); +#502 = CARTESIAN_POINT('',(822.59832299497,821.4860566353, + -332.4329207513)); +#503 = CARTESIAN_POINT('',(913.4544349676,853.06646568553, + -294.4031156001)); +#504 = CARTESIAN_POINT('',(1.057438319591E+03,887.5043108215, + -195.8936527858)); +#505 = CARTESIAN_POINT('',(1.134453238261E+03,893.64587626952, + -150.1143904698)); +#506 = CARTESIAN_POINT('',(1.22525177331E+03,975.67090374394, + -78.85577121994)); +#507 = CARTESIAN_POINT('',(1.27107271388E+03,1.051437068749E+03, + -31.8051405617)); +#508 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#509 = PCURVE('',#339,#510); +#510 = DEFINITIONAL_REPRESENTATION('',(#511),#514); +#511 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#512,#513),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,3.525421054515E+03),.PIECEWISE_BEZIER_KNOTS.); +#512 = CARTESIAN_POINT('',(0.,1.)); +#513 = CARTESIAN_POINT('',(3.533404360598E+03,1.)); +#514 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#515 = PCURVE('',#516,#621); +#516 = B_SPLINE_SURFACE_WITH_KNOTS('',3,1,( + (#517,#518) + ,(#519,#520) + ,(#521,#522) + ,(#523,#524) + ,(#525,#526) + ,(#527,#528) + ,(#529,#530) + ,(#531,#532) + ,(#533,#534) + ,(#535,#536) + ,(#537,#538) + ,(#539,#540) + ,(#541,#542) + ,(#543,#544) + ,(#545,#546) + ,(#547,#548) + ,(#549,#550) + ,(#551,#552) + ,(#553,#554) + ,(#555,#556) + ,(#557,#558) + ,(#559,#560) + ,(#561,#562) + ,(#563,#564) + ,(#565,#566) + ,(#567,#568) + ,(#569,#570) + ,(#571,#572) + ,(#573,#574) + ,(#575,#576) + ,(#577,#578) + ,(#579,#580) + ,(#581,#582) + ,(#583,#584) + ,(#585,#586) + ,(#587,#588) + ,(#589,#590) + ,(#591,#592) + ,(#593,#594) + ,(#595,#596) + ,(#597,#598) + ,(#599,#600) + ,(#601,#602) + ,(#603,#604) + ,(#605,#606) + ,(#607,#608) + ,(#609,#610) + ,(#611,#612) + ,(#613,#614) + ,(#615,#616) + ,(#617,#618) + ,(#619,#620 + )),.UNSPECIFIED.,.T.,.F.,.F.,(4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,4),(2,2),(0.,245.93425669822,294.89464339225, + 576.40705430156,599.44015679986,825.35863341498,835.7857673874, + 1.056714115237E+03,1.062201306783E+03,1.308410733039E+03, + 1.308503081198E+03,1.605147086155E+03,1.617815220003E+03, + 1.927844505098E+03,1.948298070295E+03,2.226134846647E+03, + 2.257677133181E+03,2.504085355645E+03,2.53658784644E+03, + 2.760245383322E+03,2.780433146279E+03,3.06139843273E+03, + 3.071972537268E+03,3.30856116683E+03,3.32614492816E+03, + 3.525421054515E+03),(0.,1.),.UNSPECIFIED.); +#517 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#518 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#519 = CARTESIAN_POINT('',(1.202713388734E+03,1.201284356179E+03, + 62.853462083628)); +#520 = CARTESIAN_POINT('',(1.166057269021E+03,1.161560747493E+03, + 55.481330741842)); +#521 = CARTESIAN_POINT('',(1.088086272215E+03,1.202523244816E+03, + 95.776331213073)); +#522 = CARTESIAN_POINT('',(1.042033497262E+03,1.156578280013E+03, + 75.069470515965)); +#523 = CARTESIAN_POINT('',(1.000569009003E+03,1.16381934727E+03, + 115.57506677041)); +#524 = CARTESIAN_POINT('',(985.85302939548,1.109715971885E+03, + 86.285597020484)); +#525 = CARTESIAN_POINT('',(987.68910607487,1.156065107357E+03, + 118.21176644974)); +#526 = CARTESIAN_POINT('',(976.90716960524,1.100777675124E+03, + 88.464087217588)); +#527 = CARTESIAN_POINT('',(917.94258591393,1.097886828629E+03, + 132.13628191005)); +#528 = CARTESIAN_POINT('',(919.69262837613,1.033667902514E+03, + 105.05393389749)); +#529 = CARTESIAN_POINT('',(912.53346093188,988.79012419722, + 160.86740524197)); +#530 = CARTESIAN_POINT('',(886.47235429077,943.30199597359, + 128.4209161799)); +#531 = CARTESIAN_POINT('',(910.99845453676,876.77245824724, + 191.1031862944)); +#532 = CARTESIAN_POINT('',(885.37306115443,841.23787057247, + 156.08653102374)); +#533 = CARTESIAN_POINT('',(910.90907232865,868.33760333009, + 193.3847150011)); +#534 = CARTESIAN_POINT('',(885.16365639997,833.65236176629, + 158.21717617621)); +#535 = CARTESIAN_POINT('',(909.93561874161,777.95707997853, + 217.88335973648)); +#536 = CARTESIAN_POINT('',(881.63500679981,753.02055248361, + 181.47048635563)); +#537 = CARTESIAN_POINT('',(892.37442693947,708.94717919312, + 246.02734063944)); +#538 = CARTESIAN_POINT('',(867.17033879378,691.91495175403, + 204.56967545344)); +#539 = CARTESIAN_POINT('',(872.44397768611,641.67268822425, + 257.79401451541)); +#540 = CARTESIAN_POINT('',(849.33448442783,632.42902426024, + 213.54449494129)); +#541 = CARTESIAN_POINT('',(871.56150893165,638.71468072271, + 258.27714526472)); +#542 = CARTESIAN_POINT('',(848.56303278912,629.76125572807, + 213.90612685975)); +#543 = CARTESIAN_POINT('',(851.944150604,573.28710258968,268.14839932447 + )); +#544 = CARTESIAN_POINT('',(831.77195714405,569.67684033369, + 221.17796622322)); +#545 = CARTESIAN_POINT('',(838.69659981287,491.20650535871, + 261.12675301092)); +#546 = CARTESIAN_POINT('',(822.32877333063,494.244185359,212.90715989339 + )); +#547 = CARTESIAN_POINT('',(827.19916554756,418.1049870085, + 239.71225054204)); +#548 = CARTESIAN_POINT('',(812.08088821017,429.01879743557, + 193.01703501534)); +#549 = CARTESIAN_POINT('',(826.92177616239,416.34000001561, + 239.18471058912)); +#550 = CARTESIAN_POINT('',(811.81977666655,427.43488921949, + 192.53594382717)); +#551 = CARTESIAN_POINT('',(814.2529446594,335.70585554527, + 214.59576977926)); +#552 = CARTESIAN_POINT('',(799.26201525971,354.65684215134, + 170.51433605328)); +#553 = CARTESIAN_POINT('',(788.57332926242,246.8943796104, + 180.38607780955)); +#554 = CARTESIAN_POINT('',(761.49384329249,278.00419854781, + 150.99050583725)); +#555 = CARTESIAN_POINT('',(727.55830204535,201.0446264089, + 166.38004646877)); +#556 = CARTESIAN_POINT('',(706.86217902163,236.99792194868, + 138.46880064011)); +#557 = CARTESIAN_POINT('',(727.53542015965,201.0274415914, + 166.37479790344)); +#558 = CARTESIAN_POINT('',(706.84168970447,236.98255061732, + 138.46410680441)); +#559 = CARTESIAN_POINT('',(653.99457325372,145.82801924528, + 149.51906383064)); +#560 = CARTESIAN_POINT('',(640.98616107366,187.60217057505, + 123.38504922427)); +#561 = CARTESIAN_POINT('',(520.01409755392,129.1433526287, + 140.19551295739)); +#562 = CARTESIAN_POINT('',(515.63408268306,174.59673783698, + 119.03753895297)); +#563 = CARTESIAN_POINT('',(437.34286343304,144.39625058295, + 101.59468679523)); +#564 = CARTESIAN_POINT('',(446.06923991212,190.76179806199, + 82.153564370601)); +#565 = CARTESIAN_POINT('',(434.05674247195,145.07805098043, + 99.963248198461)); +#566 = CARTESIAN_POINT('',(443.25212064465,191.47618320384, + 80.52911384442)); +#567 = CARTESIAN_POINT('',(353.11819862887,163.88606352861, + 57.048823685604)); +#568 = CARTESIAN_POINT('',(372.33230990464,210.96326635596, + 36.422971651468)); +#569 = CARTESIAN_POINT('',(294.56812450218,215.63274158357, + -55.6794103871)); +#570 = CARTESIAN_POINT('',(323.9734395583,260.00308236508, + -70.05246522855)); +#571 = CARTESIAN_POINT('',(273.484361894,278.87011712882,-144.0069789618 + )); +#572 = CARTESIAN_POINT('',(309.96990672082,317.83998914768, + -145.4385475206)); +#573 = CARTESIAN_POINT('',(272.34823817989,282.81685294064, + -149.3435718885)); +#574 = CARTESIAN_POINT('',(309.15032680045,321.61982704475, + -150.0378589026)); +#575 = CARTESIAN_POINT('',(258.32216927759,340.74683739837, + -224.8509739688)); +#576 = CARTESIAN_POINT('',(298.00397772363,379.41020524188, + -216.0373017653)); +#577 = CARTESIAN_POINT('',(253.57740885281,434.68149063597, + -279.5413023503)); +#578 = CARTESIAN_POINT('',(297.82258148459,466.96967885751, + -263.8983790846)); +#579 = CARTESIAN_POINT('',(283.30469713481,533.10288732123, + -306.7925579625)); +#580 = CARTESIAN_POINT('',(331.82221430143,553.17107491283, + -281.2540313494)); +#581 = CARTESIAN_POINT('',(286.74073372781,543.0657939886, + -309.1814581335)); +#582 = CARTESIAN_POINT('',(335.77156889379,561.8803279774, + -282.8862857798)); +#583 = CARTESIAN_POINT('',(320.8881309504,629.64182638578, + -326.6125390848)); +#584 = CARTESIAN_POINT('',(374.50555301259,637.4080935637,-296.23318306) + ); +#585 = CARTESIAN_POINT('',(389.08542892668,691.00679267604, + -341.3368003541)); +#586 = CARTESIAN_POINT('',(436.07690300895,695.92864579526, + -300.8870382141)); +#587 = CARTESIAN_POINT('',(476.8984363254,727.68416908525,-351.701981371 + )); +#588 = CARTESIAN_POINT('',(516.77450321137,720.80646129913, + -308.6004078064)); +#589 = CARTESIAN_POINT('',(487.29485514593,731.45441490903,-352.81301457 + )); +#590 = CARTESIAN_POINT('',(526.27614657826,723.51878420151, + -309.4286250346)); +#591 = CARTESIAN_POINT('',(570.00187882977,756.95170443089, + -360.7184521536)); +#592 = CARTESIAN_POINT('',(601.66997642775,743.77912017005, + -315.2080405631)); +#593 = CARTESIAN_POINT('',(646.52121639985,769.02093802401, + -363.3961926916)); +#594 = CARTESIAN_POINT('',(670.55612544275,754.76284334854, + -315.760270869)); +#595 = CARTESIAN_POINT('',(721.95555275757,790.33318722791, + -351.7919098269)); +#596 = CARTESIAN_POINT('',(737.24921538289,775.46999639197, + -302.8465069036)); +#597 = CARTESIAN_POINT('',(728.14098252971,792.15854149325, + -350.7226686196)); +#598 = CARTESIAN_POINT('',(742.77606882474,777.20105708491, + -301.6937851866)); +#599 = CARTESIAN_POINT('',(819.39423320107,820.49123726516, + -333.0533277434)); +#600 = CARTESIAN_POINT('',(825.26120343947,803.20646150145, + -283.2582232627)); +#601 = CARTESIAN_POINT('',(906.8670605001,850.78109134058,-297.134263731 + )); +#602 = CARTESIAN_POINT('',(902.70679740363,829.83344764311, + -249.9612222077)); +#603 = CARTESIAN_POINT('',(987.15639623033,870.68143078649, + -243.9466956622)); +#604 = CARTESIAN_POINT('',(975.58776570465,847.26500608648, + -200.098245837)); +#605 = CARTESIAN_POINT('',(990.05418316001,871.38747621119, + -241.9958613723)); +#606 = CARTESIAN_POINT('',(978.23455491646,847.91173479218, + -198.2851920716)); +#607 = CARTESIAN_POINT('',(1.057438319591E+03,887.5043108215, + -195.8936527858)); +#608 = CARTESIAN_POINT('',(1.04014671822E+03,863.38035893063, + -155.8209105862)); +#609 = CARTESIAN_POINT('',(1.134453238261E+03,893.64587626952, + -150.1143904698)); +#610 = CARTESIAN_POINT('',(1.100378372713E+03,885.72102739646, + -113.3455323739)); +#611 = CARTESIAN_POINT('',(1.185348720031E+03,939.62352654996, + -110.1716562067)); +#612 = CARTESIAN_POINT('',(1.148441143176E+03,924.5716438537, + -76.3084220365)); +#613 = CARTESIAN_POINT('',(1.188885451155E+03,943.04450187011, + -107.3231182047)); +#614 = CARTESIAN_POINT('',(1.151680562723E+03,927.33569807066, + -73.7903709501)); +#615 = CARTESIAN_POINT('',(1.232212109091E+03,987.83013487148, + -71.30094780836)); +#616 = CARTESIAN_POINT('',(1.190493342512E+03,962.39815064055, + -43.33013174535)); +#617 = CARTESIAN_POINT('',(1.268987723051E+03,1.056007479873E+03, + -28.91800968385)); +#618 = CARTESIAN_POINT('',(1.220653496216E+03,1.041882904981E+03, + -20.11921921824)); +#619 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#620 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#621 = DEFINITIONAL_REPRESENTATION('',(#622),#626); +#622 = LINE('',#623,#624); +#623 = CARTESIAN_POINT('',(0.,0.)); +#624 = VECTOR('',#625,1.); +#625 = DIRECTION('',(1.,0.)); +#626 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#627 = ORIENTED_EDGE('',*,*,#456,.F.); +#628 = ADVANCED_FACE('',(#629),#516,.F.); +#629 = FACE_BOUND('',#630,.F.); +#630 = EDGE_LOOP('',(#631,#632,#654,#698)); +#631 = ORIENTED_EDGE('',*,*,#478,.T.); +#632 = ORIENTED_EDGE('',*,*,#633,.T.); +#633 = EDGE_CURVE('',#457,#634,#636,.T.); +#634 = VERTEX_POINT('',#635); +#635 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#636 = SEAM_CURVE('',#637,(#640,#647),.PCURVE_S1.); +#637 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#638,#639),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,1.),.PIECEWISE_BEZIER_KNOTS.); +#638 = CARTESIAN_POINT('',(1.245358597967E+03,1.107803782579E+03, + 3.801739338516)); +#639 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#640 = PCURVE('',#516,#641); +#641 = DEFINITIONAL_REPRESENTATION('',(#642),#646); +#642 = LINE('',#643,#644); +#643 = CARTESIAN_POINT('',(3.525421054515E+03,0.)); +#644 = VECTOR('',#645,1.); +#645 = DIRECTION('',(0.,1.)); +#646 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#647 = PCURVE('',#516,#648); +#648 = DEFINITIONAL_REPRESENTATION('',(#649),#653); +#649 = LINE('',#650,#651); +#650 = CARTESIAN_POINT('',(0.,0.)); +#651 = VECTOR('',#652,1.); +#652 = DIRECTION('',(0.,1.)); +#653 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#654 = ORIENTED_EDGE('',*,*,#655,.F.); +#655 = EDGE_CURVE('',#634,#634,#656,.T.); +#656 = SURFACE_CURVE('',#657,(#686,#692),.PCURVE_S1.); +#657 = B_SPLINE_CURVE_WITH_KNOTS('',3,(#658,#659,#660,#661,#662,#663, + #664,#665,#666,#667,#668,#669,#670,#671,#672,#673,#674,#675,#676, + #677,#678,#679,#680,#681,#682,#683,#684,#685),.UNSPECIFIED.,.T.,.F., + (4,2,2,2,2,2,2,2,2,2,2,2,2,4),(0.,222.00403323393,520.32072537362, + 745.0484854878,953.89230726678,1.181098004649E+03,1.448960920875E+03 + ,1.740258804631E+03,2.009524501033E+03,2.26042949843E+03, + 2.49166430102E+03,2.763514154257E+03,3.002499932648E+03, + 3.182385827244E+03),.UNSPECIFIED.); +#658 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#659 = CARTESIAN_POINT('',(1.166057269021E+03,1.161560747493E+03, + 55.481330741842)); +#660 = CARTESIAN_POINT('',(1.042033497262E+03,1.156578280013E+03, + 75.069470515965)); +#661 = CARTESIAN_POINT('',(932.22201469412,1.064980261565E+03, + 96.992738991696)); +#662 = CARTESIAN_POINT('',(886.64908261109,959.71037773339, + 123.97324205157)); +#663 = CARTESIAN_POINT('',(884.5575816291,765.52448550344, + 176.60948501576)); +#664 = CARTESIAN_POINT('',(868.90853507648,697.7121631419, + 203.69503286265)); +#665 = CARTESIAN_POINT('',(832.66209593812,576.8234741981,221.9338703004 + )); +#666 = CARTESIAN_POINT('',(822.80072005024,497.24801566188, + 213.82316149551)); +#667 = CARTESIAN_POINT('',(800.93710398683,358.09122161299, + 171.38805916219)); +#668 = CARTESIAN_POINT('',(762.71094539038,278.91774979948, + 151.26946848406)); +#669 = CARTESIAN_POINT('',(641.06421339458,187.61027077289, + 123.38775306176)); +#670 = CARTESIAN_POINT('',(515.65485194608,174.59191160042, + 119.0485510237)); +#671 = CARTESIAN_POINT('',(376.34310968249,206.96433729765, + 45.184073566389)); +#672 = CARTESIAN_POINT('',(324.51022574305,257.78606663841, + -67.16275104239)); +#673 = CARTESIAN_POINT('',(298.19714326979,366.46344939827, + -208.8155913441)); +#674 = CARTESIAN_POINT('',(295.57480912397,461.27076097379, + -262.750968003)); +#675 = CARTESIAN_POINT('',(358.90158098079,621.82708730657, + -295.0771239155)); +#676 = CARTESIAN_POINT('',(426.95073213349,693.11518920266, + -300.0147256701)); +#677 = CARTESIAN_POINT('',(581.48562987514,740.75589555926, + -314.7857322205)); +#678 = CARTESIAN_POINT('',(661.66650754441,752.00275713146, + -317.4815650448)); +#679 = CARTESIAN_POINT('',(814.09483484646,799.32934980291, + -287.966911545)); +#680 = CARTESIAN_POINT('',(897.66012529831,828.62639233363, + -253.4140041589)); +#681 = CARTESIAN_POINT('',(1.039127481215E+03,862.46233798558, + -156.6262749376)); +#682 = CARTESIAN_POINT('',(1.107444291677E+03,887.37380500749, + -108.5069618489)); +#683 = CARTESIAN_POINT('',(1.190493342512E+03,962.39815064055, + -43.33013174535)); +#684 = CARTESIAN_POINT('',(1.220653496216E+03,1.041882904981E+03, + -20.11921921824)); +#685 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#686 = PCURVE('',#516,#687); +#687 = DEFINITIONAL_REPRESENTATION('',(#688),#691); +#688 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#689,#690),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,3.182385827244E+03),.PIECEWISE_BEZIER_KNOTS.); +#689 = CARTESIAN_POINT('',(0.,1.)); +#690 = CARTESIAN_POINT('',(3.525421054515E+03,1.)); +#691 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#692 = PCURVE('',#166,#693); +#693 = DEFINITIONAL_REPRESENTATION('',(#694),#697); +#694 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#695,#696),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,3.182385827244E+03),.PIECEWISE_BEZIER_KNOTS.); +#695 = CARTESIAN_POINT('',(0.,0.)); +#696 = CARTESIAN_POINT('',(3.18959189978E+03,0.)); +#697 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#698 = ORIENTED_EDGE('',*,*,#633,.F.); +#699 = ADVANCED_FACE('',(#700),#166,.F.); +#700 = FACE_BOUND('',#701,.F.); +#701 = EDGE_LOOP('',(#702,#703,#723,#724)); +#702 = ORIENTED_EDGE('',*,*,#655,.T.); +#703 = ORIENTED_EDGE('',*,*,#704,.T.); +#704 = EDGE_CURVE('',#634,#22,#705,.T.); +#705 = SEAM_CURVE('',#706,(#709,#716),.PCURVE_S1.); +#706 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#707,#708),.UNSPECIFIED.,.F.,.F., + (2,2),(0.,1.),.PIECEWISE_BEZIER_KNOTS.); +#707 = CARTESIAN_POINT('',(1.200851639897E+03,1.085289630385E+03, + 7.300829836965)); +#708 = CARTESIAN_POINT('',(1.212034582291E+03,1.068555055781E+03, + 41.86809487572)); +#709 = PCURVE('',#166,#710); +#710 = DEFINITIONAL_REPRESENTATION('',(#711),#715); +#711 = LINE('',#712,#713); +#712 = CARTESIAN_POINT('',(3.18959189978E+03,0.)); +#713 = VECTOR('',#714,1.); +#714 = DIRECTION('',(0.,1.)); +#715 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#716 = PCURVE('',#166,#717); +#717 = DEFINITIONAL_REPRESENTATION('',(#718),#722); +#718 = LINE('',#719,#720); +#719 = CARTESIAN_POINT('',(0.,0.)); +#720 = VECTOR('',#721,1.); +#721 = DIRECTION('',(0.,1.)); +#722 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#723 = ORIENTED_EDGE('',*,*,#21,.F.); +#724 = ORIENTED_EDGE('',*,*,#704,.F.); +#725 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3) +GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#729)) GLOBAL_UNIT_ASSIGNED_CONTEXT +((#726,#727,#728)) REPRESENTATION_CONTEXT('Context #1', + '3D Context with UNIT and UNCERTAINTY') ); +#726 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) ); +#727 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) ); +#728 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() ); +#729 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#726, + 'distance_accuracy_value','confusion accuracy'); +#730 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#7)); +ENDSEC; +END-ISO-10303-21; From a6545f4f9066663fd4ea3c4568615272cc628fe2 Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 27 Dec 2024 14:10:34 -0600 Subject: [PATCH 03/15] tweak docstrings in magnet_coils.py --- parastell/magnet_coils.py | 51 +++++++++------------------------------ 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index d211954..78a33ba 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -65,7 +65,7 @@ def logger(self, logger_object): def _instantiate_filaments(self): """Extracts filament coordinate data from input data file and - instantiates MagnetCoil class objects. + instantiates Filament class objects. (Internal function not intended to be called externally) """ with open(self.coils_file, "r") as file: @@ -118,7 +118,7 @@ def _filter_filaments(self, tol=0): self.filaments = self.sort_filaments_toroidally() def import_geom_cubit(self): - """Import STEP file for magnet set into Coreform Cubit.""" + """Import geometry file for magnet set into Coreform Cubit.""" first_vol_id = 1 if cubit_io.initialized: first_vol_id += cubit.get_last_id("volume") @@ -168,7 +168,7 @@ def export_mesh(self, mesh_filename="magnet_mesh", export_dir=""): ) def sort_filaments_toroidally(self): - """Reorders list of coils by toroidal angle on range [-pi, pi]. + """Reorders list of filaments by toroidal angle on range [-pi, pi]. Returns: (list of object): sorted list of Filament class objects. @@ -255,6 +255,9 @@ def toroidal_extent(self, angle): raise e def _instantiate_coils(self): + """Instantiates MagnetCoil class objects using filament data. + (Internal function not intended to be called externally) + """ self.magnet_coils = [] for filament in self.filaments: self.magnet_coils.append( @@ -317,9 +320,7 @@ def export_step(self, step_filename="magnet_set.step", export_dir=""): self.working_dir = export_dir self.geometry_file = Path(step_filename).with_suffix(".step") - export_path = Path(self.working_dir) / Path( - self.geometry_file - ).with_suffix(".step") + export_path = Path(self.working_dir) / self.geometry_file coil_set = cq.Compound.makeCompound( [coil.solid for coil in self.magnet_coils] @@ -360,12 +361,13 @@ def import_step_cubit(self): first_vol_id += cubit.get_last_id("volume") class MagnetSetFromGeometry(MagnetSet): - """An object representing a set of modular stellarator magnet coils. + """An object representing a set of modular stellarator magnet coils + with previously defined geometry files. Arguments: coils_file (str): path to coil filament data file. geometry_file (str): path to existing coil geometry. Can be of the - types supported by + types supported by cubit_io.import_geom_to_cubit() logger (object): logger object (optional, defaults to None). If no logger is supplied, a default logger will be instantiated. @@ -420,7 +422,8 @@ def extract_solids_and_mat_tag(self): def mesh_magnets(self, min_size=20.0, max_size=50.0, max_gradient=1.5): """Creates tetrahedral mesh of magnet volumes via Coreform Cubit. class Filament(object): - """Object containing basic data defining a Filament. + """Object containing basic data defining a Filament, and necessary + functions for working with that data. Arguments: coords (2-D array of float): set of Cartesian coordinates defining @@ -606,36 +609,6 @@ def create_magnet(self): shell = cq.Shell.makeShell(face_list) self.solid = cq.Solid.makeSolid(shell) - def in_toroidal_extent(self, lower_bound, upper_bound): - """Determines if the coil lies within a given toroidal angular extent, - based on filament coordinates. - - Arguments: - lower_bound (float): lower bound of toroidal extent [rad]. - upper_bound (float): upper bound of toroidal extent [rad]. - - Returns: - in_toroidal_extent (bool): flag to indicate whether coil lies - within toroidal bounds. - """ - # Compute toroidal angle of each point in filament - toroidal_angles = np.arctan2(self.coords[:, 1], self.coords[:, 0]) - # Ensure angles are positive - toroidal_angles = (toroidal_angles + 2 * np.pi) % (2 * np.pi) - # Compute bounds of toroidal extent of filament - min_tor_ang = np.min(toroidal_angles) - max_tor_ang = np.max(toroidal_angles) - - # Determine if filament toroidal extent overlaps with that of model - if (min_tor_ang >= lower_bound or min_tor_ang <= upper_bound) or ( - max_tor_ang >= lower_bound or max_tor_ang <= upper_bound - ): - in_toroidal_extent = True - else: - in_toroidal_extent = False - - return in_toroidal_extent - def parse_args(): """Parser for running as a script""" From a479874a5990e834ba32fc59ab1029bf8494b728 Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 27 Dec 2024 14:15:24 -0600 Subject: [PATCH 04/15] tweak docstrings in parastell.py --- parastell/magnet_coils.py | 6 ++++-- parastell/parastell.py | 22 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index 78a33ba..e1b475f 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -366,8 +366,10 @@ class MagnetSetFromGeometry(MagnetSet): Arguments: coils_file (str): path to coil filament data file. - geometry_file (str): path to existing coil geometry. Can be of the - types supported by cubit_io.import_geom_to_cubit() + geometry_file (str): filename of the existing coil geometry. Can be of + the types supported by cubit_io.import_geom_to_cubit() + working_dir (str): path to directory in which existing geometry + is saved. logger (object): logger object (optional, defaults to None). If no logger is supplied, a default logger will be instantiated. diff --git a/parastell/parastell.py b/parastell/parastell.py index f11a699..b7e5bb8 100644 --- a/parastell/parastell.py +++ b/parastell/parastell.py @@ -196,7 +196,7 @@ def export_invessel_component_mesh( def construct_magnets_from_filaments( self, coils_file, width, thickness, toroidal_extent, **kwargs ): - """Constructs MagnetSet class object. + """Constructs MagnetSetFromFilaments class object. Arguments: coils_file (str): path to coil filament data file. @@ -231,6 +231,26 @@ def construct_magnets_from_filaments( def add_magnets_from_geometry( self, coils_file, geometry_file, working_dir=".", **kwargs ): + """Adds custom geometry via the MagnetSetFromGeometry class + Arguments: + coils_file (str): path to coil filament data file. + geometry_file (str): filename of the existing coil geometry. Can be of + the types supported by cubit_io.import_geom_to_cubit() + working_dir (str): path to directory in which existing geometry + is saved. + logger (object): logger object (optional, defaults to None). If no + logger is supplied, a default logger will be instantiated. + + Optional attributes: + start_line (int): starting line index for data in filament data file + (defaults to 3). + sample_mod (int): sampling modifier for filament points (defaults to + 1). For a user-defined value n, every nth point will be sampled. + scale (float): a scaling factor between the units of the point-locus + data and [cm] (defaults to m2cm = 100). + mat_tag (str): DAGMC material tag to use for magnets in DAGMC + neutronics model (defaults to 'magnets'). + """ self.magnet_set = mc.MagnetSetFromGeometry( coils_file, geometry_file, From 6da86ac8485297399186fea0e483cd4702b7e012 Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 27 Dec 2024 14:17:30 -0600 Subject: [PATCH 05/15] tweak docstrings in radial_distance_utils.py --- parastell/radial_distance_utils.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/parastell/radial_distance_utils.py b/parastell/radial_distance_utils.py index 2baf9e9..946c7c2 100644 --- a/parastell/radial_distance_utils.py +++ b/parastell/radial_distance_utils.py @@ -70,8 +70,8 @@ def build_magnet_surface(filaments, sample_mod=1): """Builds a surface in Coreform Cubit spanning a list of coil filaments. Arguments: - filaments (list of object): list of MagnetCoil class objects, - ordered toroidally. Each MagnetCoil object must also have its + filaments (list of object): list of Filament class objects, + ordered toroidally. Each Filament object must also have its filament coordinates ordered poloidally (see reorder_coils function). sample_mod (int): sampling modifier for filament points (defaults to @@ -235,8 +235,4 @@ def measure_fw_coils_separation( radial_distance_matrix = measure_surface_coils_separation(surface) - import cubit - - cubit.cmd('save cub5 "magnet_surface_test.cub5" overwrite') - return radial_distance_matrix From 6e006076c01e71e8c9578269bdefe4819a6df1b2 Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 27 Dec 2024 14:18:09 -0600 Subject: [PATCH 06/15] dont ignore magnet geometry test file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4a0afb1..a81637f 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ *.yaml !config.yaml *.lic +!magnet_geom.step # Byte-compiled / optimized / DLL files __pycache__/ From b8e5be667d906e00e6ee2e184dc24b1632172a9e Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 21 Jan 2025 09:10:58 -0600 Subject: [PATCH 07/15] remove all trace of coils file from MagnetSetFromGeometry --- parastell/magnet_coils.py | 162 +++++++++++++++++-------------------- parastell/parastell.py | 17 +--- tests/test_magnet_coils.py | 3 +- tests/test_parastell.py | 2 +- 4 files changed, 78 insertions(+), 106 deletions(-) diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index e1b475f..2febe83 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -17,42 +17,25 @@ class MagnetSet(object): """An object representing a set of modular stellarator magnet coils. Arguments: - coils_file (str): path to coil filament data file. logger (object): logger object (optional, defaults to None). If no logger is supplied, a default logger will be instantiated. Optional attributes: - start_line (int): starting line index for data in filament data file - (defaults to 3). - sample_mod (int): sampling modifier for filament points (defaults to - 1). For a user-defined value n, every nth point will be sampled. - scale (float): a scaling factor between the units of the point-locus - data and [cm] (defaults to m2cm = 100). mat_tag (str): DAGMC material tag to use for magnets in DAGMC neutronics model (defaults to 'magnets'). """ def __init__( self, - coils_file, logger=None, **kwargs, ): self.logger = logger - self.coils_file = coils_file - self.start_line = 3 - self.sample_mod = 1 - self.scale = m2cm self.mat_tag = "magnets" - for name in kwargs.keys() & ( - "start_line", - "sample_mod", - "scale", - "mat_tag", - ): + for name in kwargs.keys() & ("mat_tag",): self.__setattr__(name, kwargs[name]) @property @@ -63,60 +46,6 @@ def logger(self): def logger(self, logger_object): self._logger = log.check_init(logger_object) - def _instantiate_filaments(self): - """Extracts filament coordinate data from input data file and - instantiates Filament class objects. - (Internal function not intended to be called externally) - """ - with open(self.coils_file, "r") as file: - data = file.readlines()[self.start_line :] - - coords = [] - self.filaments = [] - - for line in data: - columns = line.strip().split() - - if columns[0] == "end": - break - - # Coil current - s = float(columns[3]) - - # s = 0 signals end of filament - if s != 0: - coords.append( - [float(ord) * self.scale for ord in columns[0:3]] - ) - - else: - coords.append(coords[0]) - self.filaments.append(Filament(np.array(coords))) - coords.clear() - - def _filter_filaments(self, tol=0): - """Filters list of Filament objects such that only those within the - toroidal extent of the model are included and filaments are sorted by - center-of-mass toroidal angle. - (Internal function not intended to be called externally) - """ - - # Compute lower and upper bounds of toroidal extent within tolerance - lower_bound = 2 * np.pi - tol - upper_bound = self._toroidal_extent + tol - - # Create filter determining whether each coil lies within model's - # toroidal extent - filtered_filaments = [ - filament - for filament in self.filaments - if filament.in_toroidal_extent(lower_bound, upper_bound) - ] - self.filaments = filtered_filaments - - # Sort coils by center-of-mass toroidal angle and overwrite stored list - self.filaments = self.sort_filaments_toroidally() - def import_geom_cubit(self): """Import geometry file for magnet set into Coreform Cubit.""" first_vol_id = 1 @@ -209,7 +138,13 @@ def __init__( logger=None, **kwargs, ): - super().__init__(coils_file, logger, **kwargs) + super().__init__(logger, **kwargs) + + self.coils_file = coils_file + + self.start_line = 3 + self.sample_mod = 1 + self.scale = m2cm self.width = width self.thickness = thickness @@ -218,6 +153,14 @@ def __init__( # Define maximum length of coil cross-section self.max_cs_len = max(self._width, self._thickness) + for name in kwargs.keys() & ( + "start_line", + "sample_mod", + "scale", + "mat_tag", + ): + self.__setattr__(name, kwargs[name]) + @property def width(self): return self._width @@ -254,6 +197,60 @@ def toroidal_extent(self, angle): self._logger.error(e.args[0]) raise e + def _instantiate_filaments(self): + """Extracts filament coordinate data from input data file and + instantiates Filament class objects. + (Internal function not intended to be called externally) + """ + with open(self.coils_file, "r") as file: + data = file.readlines()[self.start_line :] + + coords = [] + self.filaments = [] + + for line in data: + columns = line.strip().split() + + if columns[0] == "end": + break + + # Coil current + s = float(columns[3]) + + # s = 0 signals end of filament + if s != 0: + coords.append( + [float(ord) * self.scale for ord in columns[0:3]] + ) + + else: + coords.append(coords[0]) + self.filaments.append(Filament(np.array(coords))) + coords.clear() + + def _filter_filaments(self, tol=0): + """Filters list of Filament objects such that only those within the + toroidal extent of the model are included and filaments are sorted by + center-of-mass toroidal angle. + (Internal function not intended to be called externally) + """ + + # Compute lower and upper bounds of toroidal extent within tolerance + lower_bound = 2 * np.pi - tol + upper_bound = self._toroidal_extent + tol + + # Create filter determining whether each coil lies within model's + # toroidal extent + filtered_filaments = [ + filament + for filament in self.filaments + if filament.in_toroidal_extent(lower_bound, upper_bound) + ] + self.filaments = filtered_filaments + + # Sort coils by center-of-mass toroidal angle and overwrite stored list + self.filaments = self.sort_filaments_toroidally() + def _instantiate_coils(self): """Instantiates MagnetCoil class objects using filament data. (Internal function not intended to be called externally) @@ -365,36 +362,25 @@ class MagnetSetFromGeometry(MagnetSet): with previously defined geometry files. Arguments: - coils_file (str): path to coil filament data file. - geometry_file (str): filename of the existing coil geometry. Can be of + geometry_file (str): path to the existing coil geometry. Can be of the types supported by cubit_io.import_geom_to_cubit() - working_dir (str): path to directory in which existing geometry - is saved. logger (object): logger object (optional, defaults to None). If no logger is supplied, a default logger will be instantiated. Optional attributes: - start_line (int): starting line index for data in filament data file - (defaults to 3). - sample_mod (int): sampling modifier for filament points (defaults to - 1). For a user-defined value n, every nth point will be sampled. - scale (float): a scaling factor between the units of the point-locus - data and [cm] (defaults to m2cm = 100). mat_tag (str): DAGMC material tag to use for magnets in DAGMC neutronics model (defaults to 'magnets'). """ def __init__( self, - coils_file, geometry_file, - working_dir=".", logger=None, **kwargs, ): - super().__init__(coils_file, logger, **kwargs) - self.geometry_file = geometry_file - self.working_dir = Path(working_dir) + super().__init__(logger, **kwargs) + self.geometry_file = Path(geometry_file).resolve() + self.working_dir = self.geometry_file.parent for name in kwargs.keys() & ( "start_line", diff --git a/parastell/parastell.py b/parastell/parastell.py index b7e5bb8..34f4250 100644 --- a/parastell/parastell.py +++ b/parastell/parastell.py @@ -228,33 +228,20 @@ def construct_magnets_from_filaments( self.magnet_set.populate_magnet_coils() self.magnet_set.build_magnet_coils() - def add_magnets_from_geometry( - self, coils_file, geometry_file, working_dir=".", **kwargs - ): + def add_magnets_from_geometry(self, geometry_file, **kwargs): """Adds custom geometry via the MagnetSetFromGeometry class Arguments: - coils_file (str): path to coil filament data file. - geometry_file (str): filename of the existing coil geometry. Can be of + geometry_file (str): path to the existing coil geometry. Can be of the types supported by cubit_io.import_geom_to_cubit() - working_dir (str): path to directory in which existing geometry - is saved. logger (object): logger object (optional, defaults to None). If no logger is supplied, a default logger will be instantiated. Optional attributes: - start_line (int): starting line index for data in filament data file - (defaults to 3). - sample_mod (int): sampling modifier for filament points (defaults to - 1). For a user-defined value n, every nth point will be sampled. - scale (float): a scaling factor between the units of the point-locus - data and [cm] (defaults to m2cm = 100). mat_tag (str): DAGMC material tag to use for magnets in DAGMC neutronics model (defaults to 'magnets'). """ self.magnet_set = mc.MagnetSetFromGeometry( - coils_file, geometry_file, - working_dir, logger=self._logger, **kwargs, ) diff --git a/tests/test_magnet_coils.py b/tests/test_magnet_coils.py index 54657d4..0efcddd 100644 --- a/tests/test_magnet_coils.py +++ b/tests/test_magnet_coils.py @@ -46,10 +46,9 @@ def coil_set_from_filaments(): @pytest.fixture def coil_set_from_geometry(): - coils_file = Path("files_for_tests") / "coils.example" geom_file = Path("files_for_tests") / "magnet_geom.step" - coil_set_obj = magnet_coils.MagnetSetFromGeometry(coils_file, geom_file) + coil_set_obj = magnet_coils.MagnetSetFromGeometry(geom_file) return coil_set_obj diff --git a/tests/test_parastell.py b/tests/test_parastell.py index 79686ea..96a1f83 100644 --- a/tests/test_parastell.py +++ b/tests/test_parastell.py @@ -164,7 +164,7 @@ def test_parastell(stellarator): stellarator.export_invessel_build() - stellarator.add_magnets_from_geometry(coils_file, geometry_file) + stellarator.add_magnets_from_geometry(geometry_file) stellarator.build_cubit_model() From 41357a366d66361c11ebd0e9508f17d1fd37abde Mon Sep 17 00:00:00 2001 From: Edgar Date: Mon, 27 Jan 2025 12:06:46 -0600 Subject: [PATCH 08/15] move sort_filaments_toroidally to MagnetSetFromFilaments --- parastell/magnet_coils.py | 16 ++++++++-------- tests/test_parastell.py | 4 ---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index 2febe83..e31fa5f 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -96,14 +96,6 @@ def export_mesh(self, mesh_filename="magnet_mesh", export_dir=""): filename=mesh_filename, export_dir=export_dir ) - def sort_filaments_toroidally(self): - """Reorders list of filaments by toroidal angle on range [-pi, pi]. - - Returns: - (list of object): sorted list of Filament class objects. - """ - return sorted(self.filaments, key=lambda x: x.com_toroidal_angle) - class MagnetSetFromFilaments(MagnetSet): """Inherits from MagnetSet. This subclass enables the construction of @@ -228,6 +220,14 @@ def _instantiate_filaments(self): self.filaments.append(Filament(np.array(coords))) coords.clear() + def sort_filaments_toroidally(self): + """Reorders list of filaments by toroidal angle on range [-pi, pi]. + + Returns: + (list of object): sorted list of Filament class objects. + """ + return sorted(self.filaments, key=lambda x: x.com_toroidal_angle) + def _filter_filaments(self, tol=0): """Filters list of Filament objects such that only those within the toroidal extent of the model are included and filaments are sorted by diff --git a/tests/test_parastell.py b/tests/test_parastell.py index 96a1f83..c5a5ee5 100644 --- a/tests/test_parastell.py +++ b/tests/test_parastell.py @@ -168,10 +168,6 @@ def test_parastell(stellarator): stellarator.build_cubit_model() - import cubit - - cubit.cmd('save cub5 "test.cub5"') - assert ( stellarator.invessel_build.radial_build.radial_build["chamber"][ "vol_id" From 8a790f14c381c0bb57c53935c98ba08cf5916f82 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 28 Jan 2025 15:23:05 -0600 Subject: [PATCH 09/15] group test files in gitignore --- .gitignore | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a81637f..438e948 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# PRoject specific +# Project specific *.csv *.step *.h5m @@ -12,12 +12,14 @@ *.cub5 *.h5 *.exo -!wout_vmec.nc .vscode *.yaml -!config.yaml *.lic + +# Exceptions for tests !magnet_geom.step +!config.yaml +!wout_vmec.nc # Byte-compiled / optimized / DLL files __pycache__/ From 18b65b27914189d1048264c6ab52ec8544ce6be7 Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 29 Jan 2025 12:50:12 -0600 Subject: [PATCH 10/15] clean up after rebase --- parastell/magnet_coils.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index e31fa5f..9a96996 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -357,6 +357,7 @@ def import_step_cubit(self): if cubit_io.initialized: first_vol_id += cubit.get_last_id("volume") + class MagnetSetFromGeometry(MagnetSet): """An object representing a set of modular stellarator magnet coils with previously defined geometry files. @@ -390,10 +391,6 @@ def __init__( ): self.__setattr__(name, kwargs[name]) - - coil_set = cq.Compound.makeCompound(self.coil_solids) - cq.exporters.export(coil_set, str(export_path)) - def extract_solids_and_mat_tag(self): """Appends magnet set CadQuery solid objects and material tag to corresponding input lists. @@ -407,8 +404,7 @@ def extract_solids_and_mat_tag(self): return solids, mat_tags - def mesh_magnets(self, min_size=20.0, max_size=50.0, max_gradient=1.5): - """Creates tetrahedral mesh of magnet volumes via Coreform Cubit. + class Filament(object): """Object containing basic data defining a Filament, and necessary functions for working with that data. From 0fa2477fe8f4b3d89a4dfaab84904ff720dd6d4e Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 29 Jan 2025 17:10:12 -0600 Subject: [PATCH 11/15] update to have magnets work with new cad to dagmc workflow --- Examples/parastell_cad_to_dagmc_example.py | 2 +- parastell/invessel_build.py | 8 ++++++ parastell/magnet_coils.py | 30 ++++++++++++---------- parastell/parastell.py | 22 +++------------- tests/test_magnet_coils.py | 1 + tests/test_parastell.py | 9 ++++++- 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/Examples/parastell_cad_to_dagmc_example.py b/Examples/parastell_cad_to_dagmc_example.py index e5b9cbd..704ed9f 100644 --- a/Examples/parastell_cad_to_dagmc_example.py +++ b/Examples/parastell_cad_to_dagmc_example.py @@ -56,7 +56,7 @@ thickness = 50.0 toroidal_extent = 90.0 # Construct magnets -stellarator.construct_magnets( +stellarator.construct_magnets_from_filaments( coils_file, width, thickness, toroidal_extent, sample_mod=6 ) # Export magnet files diff --git a/parastell/invessel_build.py b/parastell/invessel_build.py index 6c75b5f..556d00a 100644 --- a/parastell/invessel_build.py +++ b/parastell/invessel_build.py @@ -329,6 +329,14 @@ def extract_solids_and_mat_tags(self): return solids, mat_tags + def add_solids_to_cad_to_dagmc(self, dagmc_model): + """Add in vessel build geomtry to the cad_to_dagmc dagmc model with + appropriate material tags. + """ + solids, mat_tags = self.extract_solids_and_mat_tags() + for solid, mat_tag in zip(solids, mat_tags): + dagmc_model.add_cadquery_object(solid, material_tags=[mat_tag]) + def export_component_mesh( self, components, mesh_size=5, import_dir="", export_dir="" ): diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index 9a96996..77c6e65 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -1,5 +1,6 @@ import argparse from pathlib import Path +from abc import ABC, abstractmethod import numpy as np @@ -13,7 +14,7 @@ export_allowed_kwargs = ["step_filename", "export_mesh", "mesh_filename"] -class MagnetSet(object): +class MagnetSet(ABC): """An object representing a set of modular stellarator magnet coils. Arguments: @@ -96,6 +97,12 @@ def export_mesh(self, mesh_filename="magnet_mesh", export_dir=""): filename=mesh_filename, export_dir=export_dir ) + def add_solids_to_cad_to_dagmc(self, dagmc_model): + for solid in self.coil_solids: + dagmc_model.add_cadquery_object( + solid, material_tags=[self.mat_tag] + ) + class MagnetSetFromFilaments(MagnetSet): """Inherits from MagnetSet. This subclass enables the construction of @@ -364,7 +371,8 @@ class MagnetSetFromGeometry(MagnetSet): Arguments: geometry_file (str): path to the existing coil geometry. Can be of - the types supported by cubit_io.import_geom_to_cubit() + the types supported by cubit_io.import_geom_to_cubit(). For + cad_to_dagmc, only step files are supported. logger (object): logger object (optional, defaults to None). If no logger is supplied, a default logger will be instantiated. @@ -391,18 +399,14 @@ def __init__( ): self.__setattr__(name, kwargs[name]) - def extract_solids_and_mat_tag(self): - """Appends magnet set CadQuery solid objects and material tag to - corresponding input lists. - - Returns: - solids (list): list of magnet set CadQuery solid objects. - mat_tags (list): list of magnet set material tags. - """ - solids = self.coil_solids - mat_tags = [self.mat_tag] * len(self.coil_solids) + def get_cq_solids(self): + self.coil_solids = ( + cq.importers.importStep(str(self.geometry_file)).val().Solids() + ) - return solids, mat_tags + def add_solids_to_cad_to_dagmc(self, dagmc_model): + self.get_cq_solids() + super().add_solids_to_cad_to_dagmc(dagmc_model) class Filament(object): diff --git a/parastell/parastell.py b/parastell/parastell.py index 34f4250..8d3178e 100644 --- a/parastell/parastell.py +++ b/parastell/parastell.py @@ -441,29 +441,13 @@ def build_cad_to_dagmc_model(self): "Building DAGMC neutronics model via CAD-to-DAGMC..." ) - solids = [] - material_names = [] + self.dagmc_model = cad_to_dagmc.CadToDagmc() if self.invessel_build: - ivb_solids, ivb_material_names = ( - self.invessel_build.extract_solids_and_mat_tags() - ) - solids.extend(ivb_solids) - material_names.extend(ivb_material_names) + self.invessel_build.add_solids_to_cad_to_dagmc(self.dagmc_model) if self.magnet_set: - ms_solids, ms_material_names = ( - self.magnet_set.extract_solids_and_mat_tag() - ) - solids.extend(ms_solids) - material_names.extend(ms_material_names) - - self.dagmc_model = cad_to_dagmc.CadToDagmc() - - for solid, mat_tag in zip(solids, material_names): - self.dagmc_model.add_cadquery_object( - solid, material_tags=[mat_tag] - ) + self.magnet_set.add_solids_to_cad_to_dagmc(self.dagmc_model) def export_cad_to_dagmc( self, diff --git a/tests/test_magnet_coils.py b/tests/test_magnet_coils.py index 0efcddd..e8451be 100644 --- a/tests/test_magnet_coils.py +++ b/tests/test_magnet_coils.py @@ -104,6 +104,7 @@ def test_magnet_construction(coil_set_from_filaments): remove_files() coil_set_from_filaments.populate_magnet_coils() + coil_set_from_filaments.build_magnet_coils() assert len(coil_set_from_filaments.magnet_coils) == len_coils_exp assert coil_set_from_filaments.width == width_exp diff --git a/tests/test_parastell.py b/tests/test_parastell.py index c5a5ee5..d7c4a42 100644 --- a/tests/test_parastell.py +++ b/tests/test_parastell.py @@ -182,10 +182,17 @@ def test_parastell(stellarator): ) assert stellarator.magnet_set.volume_ids == magnet_volume_ids_exp - stellarator.export_dagmc(filename=filename_exp) + stellarator.export_cubit_dagmc(filename=filename_exp) stellarator.export_cub5(filename=filename_exp) assert Path(filename_exp).with_suffix(".h5m").exists() assert Path(filename_exp).with_suffix(".cub5").exists() remove_files() + + stellarator.build_cad_to_dagmc_model() + stellarator.export_cad_to_dagmc(min_mesh_size=50, max_mesh_size=100) + + assert Path(filename_exp).with_suffix(".h5m").exists() + + remove_files() From 289c4a79b13429c42a30a34c2024b27136d2aaf9 Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 29 Jan 2025 17:16:13 -0600 Subject: [PATCH 12/15] add docstrings to new MagnetCoil method --- parastell/magnet_coils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index 77c6e65..f894dd9 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -98,6 +98,9 @@ def export_mesh(self, mesh_filename="magnet_mesh", export_dir=""): ) def add_solids_to_cad_to_dagmc(self, dagmc_model): + """Add the magnet solids to a cad_to_dagmc model with the magnet + material tag. + """ for solid in self.coil_solids: dagmc_model.add_cadquery_object( solid, material_tags=[self.mat_tag] @@ -400,6 +403,7 @@ def __init__( self.__setattr__(name, kwargs[name]) def get_cq_solids(self): + """Load the provided geometry into cadquery for use with cad_to_dagmc.""" self.coil_solids = ( cq.importers.importStep(str(self.geometry_file)).val().Solids() ) From 16c542f6ea2fe36cefc6f30afa9c676c3f5ae4d2 Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 29 Jan 2025 17:19:10 -0600 Subject: [PATCH 13/15] remove unused import --- parastell/magnet_coils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index f894dd9..47ee334 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -1,6 +1,6 @@ import argparse from pathlib import Path -from abc import ABC, abstractmethod +from abc import ABC import numpy as np From f81059fe8a4f7c43516d4c45647e873164ee935b Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 31 Jan 2025 15:08:06 -0600 Subject: [PATCH 14/15] add solids in stellarator --- parastell/invessel_build.py | 8 -------- parastell/magnet_coils.py | 26 ++++++++------------------ parastell/parastell.py | 12 ++++++++++-- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/parastell/invessel_build.py b/parastell/invessel_build.py index 556d00a..6c75b5f 100644 --- a/parastell/invessel_build.py +++ b/parastell/invessel_build.py @@ -329,14 +329,6 @@ def extract_solids_and_mat_tags(self): return solids, mat_tags - def add_solids_to_cad_to_dagmc(self, dagmc_model): - """Add in vessel build geomtry to the cad_to_dagmc dagmc model with - appropriate material tags. - """ - solids, mat_tags = self.extract_solids_and_mat_tags() - for solid, mat_tag in zip(solids, mat_tags): - dagmc_model.add_cadquery_object(solid, material_tags=[mat_tag]) - def export_component_mesh( self, components, mesh_size=5, import_dir="", export_dir="" ): diff --git a/parastell/magnet_coils.py b/parastell/magnet_coils.py index 47ee334..8934bd2 100644 --- a/parastell/magnet_coils.py +++ b/parastell/magnet_coils.py @@ -97,15 +97,6 @@ def export_mesh(self, mesh_filename="magnet_mesh", export_dir=""): filename=mesh_filename, export_dir=export_dir ) - def add_solids_to_cad_to_dagmc(self, dagmc_model): - """Add the magnet solids to a cad_to_dagmc model with the magnet - material tag. - """ - for solid in self.coil_solids: - dagmc_model.add_cadquery_object( - solid, material_tags=[self.mat_tag] - ) - class MagnetSetFromFilaments(MagnetSet): """Inherits from MagnetSet. This subclass enables the construction of @@ -393,6 +384,7 @@ def __init__( super().__init__(logger, **kwargs) self.geometry_file = Path(geometry_file).resolve() self.working_dir = self.geometry_file.parent + self._coil_solids = None for name in kwargs.keys() & ( "start_line", @@ -402,15 +394,13 @@ def __init__( ): self.__setattr__(name, kwargs[name]) - def get_cq_solids(self): - """Load the provided geometry into cadquery for use with cad_to_dagmc.""" - self.coil_solids = ( - cq.importers.importStep(str(self.geometry_file)).val().Solids() - ) - - def add_solids_to_cad_to_dagmc(self, dagmc_model): - self.get_cq_solids() - super().add_solids_to_cad_to_dagmc(dagmc_model) + @property + def coil_solids(self): + if self._coil_solids is None: + self._coil_solids = ( + cq.importers.importStep(str(self.geometry_file)).val().Solids() + ) + return self._coil_solids class Filament(object): diff --git a/parastell/parastell.py b/parastell/parastell.py index 8d3178e..2a4ba6b 100644 --- a/parastell/parastell.py +++ b/parastell/parastell.py @@ -444,10 +444,18 @@ def build_cad_to_dagmc_model(self): self.dagmc_model = cad_to_dagmc.CadToDagmc() if self.invessel_build: - self.invessel_build.add_solids_to_cad_to_dagmc(self.dagmc_model) + for solid, mat_tag in zip( + *self.invessel_build.extract_solids_and_mat_tags() + ): + self.dagmc_model.add_cadquery_object( + solid, material_tags=[mat_tag] + ) if self.magnet_set: - self.magnet_set.add_solids_to_cad_to_dagmc(self.dagmc_model) + for solid in self.magnet_set.coil_solids: + self.dagmc_model.add_cadquery_object( + solid, material_tags=[self.magnet_set.mat_tag] + ) def export_cad_to_dagmc( self, From f53be7bd169062c846b08325d041ad5ea28fff9e Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 31 Jan 2025 15:21:01 -0600 Subject: [PATCH 15/15] update docstring of ivb.extract_solids_and_mat_tags --- parastell/invessel_build.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parastell/invessel_build.py b/parastell/invessel_build.py index 6c75b5f..d523f9a 100644 --- a/parastell/invessel_build.py +++ b/parastell/invessel_build.py @@ -313,8 +313,8 @@ def export_step(self, export_dir=""): cq.exporters.export(component, str(export_path)) def extract_solids_and_mat_tags(self): - """Appends in-vessel component CadQuery solid objects and material - tags to corresponding input lists. + """Get a list of all cadquery solids, and a corresponding list of + the respective material tags. Returns: solids (list): list of in-vessel component CadQuery solid objects.