Source code for comet.pyhed.IO.saveload

"""
Part of comet/pyhed/IO
"""
# COMET - COupled Magnetic resonance Electrical resistivity Tomography
# Copyright (C) 2019  Nico Skibbe

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import numpy as np
import os
from pathlib import Path


[docs]class ArgsError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value)
[docs]def cutExtension(path): filename = os.path.split(path)[1].split('.')[0] return os.path.join(os.path.dirname(path), filename)
[docs]class TetgenNotFoundError(Exception): """ Special Exception to catch in a try except. """ pass
[docs]def searchforTetgen(returnPathfile=False): """ Try to find a valid tetgen installation for meshing purposes. Returns: -------- path: string Path to tetgen installation or path to pathfile of pyhed itself. """ import comet.pyhed as ph import sys import subprocess as sp if sys.version_info[:2] < (3, 3): error = IOError else: error = FileNotFoundError pathfile = os.path.join(os.path.dirname(ph.__file__), '_PATH_.txt') try: p = sp.Popen(['tetgen'], stdout=sp.PIPE) _, err = p.communicate() PATH = None except FileNotFoundError: try: with open(pathfile, 'r') as pathf: PATH = pathf.readline() while PATH.lstrip().startswith('#'): PATH = pathf.readline() try: try: PATH = PATH.split('TETGENPATH: ')[1].rstrip() except TypeError: PATH = PATH.decode().split('TETGENPATH: ')[1].rstrip() except IndexError: PATH = '' if PATH in ['Enter/path/here/', '']: raise error except error: with open(pathfile, 'w') as pathf: try: p = sp.Popen(['which', 'tetgen'], stdout=sp.PIPE) out, err = p.communicate() # print(out, err) if len(out) > 0: try: PATH = Path(out.split('tetgen')[0]) except TypeError: PATH = Path(out.decode().split('tetgen')[0]) if not PATH.exists(): # windows root not detected corretly # there is a special case that can be intercepted import platform if platform.system() == 'Windows': if PATH.drive == '': parts = PATH.parts if parts[0] == '\\': PATH = Path('{}:/'.format(parts[1]), *parts[2:]) if PATH.exists(): pathf.writelines('TETGENPATH: {}' .format(PATH.as_posix())) else: raise error except error: pathf.writelines('TETGENPATH: Enter/path/here/') raise Exception( 'Tetgen not found. Please add or link a ' 'executabe tetgen instance to your PATH or alter file' 'in "{}"'.format(pathfile)) if returnPathfile is True: return pathfile else: if PATH is None: return None else: return Path(PATH).as_posix()
[docs]def getItem(archive, key, default=None): """ Get item for *key* from numpy *archive* via try except with given *default* value for None. """ try: item = archive[key].item() except ValueError: item = archive[key] except KeyError: item = default return item
[docs]def checkDirectory(savename, filename=False, verbose=False): """ Checks for directory and creates if not. """ from comet.pyhed import log if '.' in savename and filename is False and not savename.startswith('.'): filename = True if filename is True: dirname = os.path.dirname(savename) if dirname == '': if '.' in savename: directory = '.' else: return else: directory = os.path.abspath(dirname) else: directory = savename exists = os.path.exists(directory) log.debug('checkDirectory: "{}" exists? : {}'.format(directory, exists)) log.debug('todo: replace "checkDirectory" with proper pathlib tools') if not exists: os.makedirs(directory)
[docs]def checkForFile(name): """ Checks if file exists and creates a directory if it does not.""" if os.path.exists(name): return True else: checkDirectory(name) return False
[docs]def delLastLine(opened_file, line_ending='\n'): """ Efficient way of deleting the last line of a large file. """ opened_file.seek(0, os.SEEK_END) # end of file pos = opened_file.tell() - 1 while pos > 0 and opened_file.read(1) != line_ending: pos -= 1 opened_file.seek(pos, os.SEEK_SET) if pos > 0: opened_file.seek(pos, os.SEEK_SET) opened_file.truncate() return opened_file
[docs]def addVolumeConstraintToPoly(name, regions, float_format='6.3f'): ''' Append region information in form of volume constraints to a tetgen.poly file. The given regions has to be of shape (n, 5 or 6), with n times: [number, x, y, z, regional attribute, volume constraint] ''' with open(name, "r+") as in_file: string = '{}' for i in range(len(regions[0]) - 1): # either 4 or 5 floats possible string += ' {:%s}' % (float_format) string += os.linesep delLastLine(in_file) in_file.seek(0, os.SEEK_END) in_file.write(os.linesep) lines = '# volume constraints{}'.format(os.linesep) lines += '{:d}{}'.format(len(regions), os.linesep) for region in regions: lines += string.format(*region) in_file.write(lines)
[docs]def createCustEMDirectories(m_dir='.', r_dir='.'): """ Creates the used custEM directories based on *m_dir* and *r_dir*. """ m_path = Path(m_dir) r_path = Path(r_dir) m_path.joinpath('_h5').mkdir(exist_ok=True, parents=True) m_path.joinpath('_mesh').mkdir(exist_ok=True) m_path.joinpath('para').mkdir(exist_ok=True) r_path.joinpath('primary_fields/custom').mkdir(exist_ok=True, parents=True) r_path.joinpath('E_s').mkdir(exist_ok=True) r_path.joinpath('H_s').mkdir(exist_ok=True)
#def exportTetgenPolyFile(filename, poly, float_format='.12e'): # ''' # Writes a given piecewise linear complex (mesh/poly ) into a Ascii file in # tetgen's .poly format. # # Parameters # ---------- # # filename: string # Name in which the result will be written. The recommended file # ending is '.poly'. # # poly: pg.Mesh # Piecewise linear complex as pygimli mesh to be exported. # # float_format: format string ('.12e') # Format that will be used to write float values in the Ascii file. # Default is the exponential float form with a precision of 12 digits. # # ''' # filename = filename.rstrip('.poly') + '.poly' # polytxt = '' # sep = '\t' # standard tab seperated file # assert poly.dim() == 3, 'Exit, only for 3D meshes.' # boundary_marker = 1 # attribute_count = 0 # # # Part 1/4: node list # # intro line # # <nodecount> <dimension (3)> <# of attributes> <boundary markers (0 or 1)> # polytxt += '{0}{5}{1}{5}{2}{5}{3}{4}'.format(poly.nodeCount(), 3, # attribute_count, # boundary_marker, # os.linesep, sep) # # loop over positions, attributes and marker(node) # # <point idx> <x> <y> <z> [attributes] [boundary marker] # point_str = '{:d}' # index of the point # for i in range(3): # # coords as float with given precision # point_str += sep + '{:%s}' % (float_format) # point_str += sep + '{:d}' + os.linesep # node marker # for j, node in enumerate(poly.nodes()): # fill = [node.id()] # fill.extend([pos for pos in node.pos()]) # fill.append(node.marker()) # polytxt += point_str.format(*fill) # # # Part 2/4: boundary list # # intro line # # <# of facets> <boundary markers (0 or 1)> # polytxt += '{0:d}{2}1{1}'.format(poly.boundaryCount(), os.linesep, sep) # # loop over facets, each facet can contain an arbitrary number of holes # # and polygons, in our case, there is always one polygon per facet. # for k, bound in enumerate(poly.boundaries()): # # one line per facet # # <# of polygons> [# of holes] [boundary marker] # npolys = 1 # polytxt += '1{2}0{2}{0:d}{1}'.format(bound.marker(), os.linesep, sep) # # inner loop over polygons # # <# of corners> <corner 1> <corner 2> ... <corner #> # for l in range(npolys): # poly_str = '{:d}'.format(bound.nodeCount()) # for ind in bound.ids(): # poly_str += sep + '{:d}'.format(ind) # polytxt += '{0}{1}'.format(poly_str, os.linesep) # # inner loop over holes # # not necessary yet ?! why is there an extra hole section? # # because this is for 2D holes in facets only # # # part 3/4: hole list # # intro line # # <# of holes> # holes = poly.holeMarker() # polytxt += '{:d}{}'.format(len(holes), os.linesep) # # loop over hole markers # # <hole #> <x> <y> <z> # hole_str = '{:d}' # for m in range(3): # hole_str += sep + '{:%s}' % float_format # hole_str += os.linesep # for n, hole in enumerate(holes): # polytxt += hole_str.format(n, *hole) # # # part 4/4: region attributes and volume constraints (optional) # # intro line # # <# of regions> # regions = poly.regionMarker() # polytxt += '{:d}{}'.format(len(regions), os.linesep) # # loop over region markers # # <region #> <x> <y> <z> <region number> <region attribute> # region_str = '{:d}' # for o in range(3): # region_str += sep + '{:%s}' % (float_format) # region_str += sep + '{:d}%s{:%s}' % (sep, float_format) + os.linesep # for p, region in enumerate(regions): # polytxt += region_str.format(p, region.x(), region.y(), region.z(), # region.marker(), # region.area()) # # # writing file # with open(filename, 'w') as out: # out.write(polytxt) # THE END