#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Classes
-------
.. autosummary::
:nosignatures:
:toctree: classes/
SkeletonGeometry
QuadSkeletonGeometry
TriSkeletonGeometry
FixedDict
OOF2
"""
import os.path
import re
from collections import namedtuple
from abc import ABC, abstractmethod
import numpy as np
[docs]class SkeletonGeometry(ABC):
[docs] @abstractmethod
def __init__(self, leftright_periodicity, topbottom_periodicity):
self.leftright_periodicity = leftright_periodicity
self.topbottom_periodicity = topbottom_periodicity
[docs]class QuadSkeletonGeometry(SkeletonGeometry):
[docs] def __init__(self, leftright_periodicity=False,
topbottom_periodicity=False):
super().__init__(leftright_periodicity, topbottom_periodicity)
def __repr__(self):
repr_OOF = "QuadSkeleton(left_right_periodicity={1}, " \
"top_bottom_periodicity={2})".format(self.leftright_periodicity,
self.topbottom_periodicity)
return repr_OOF
[docs]class TriSkeletonGeometry(SkeletonGeometry):
[docs] def __init__(self, leftright_periodicity=False,
topbottom_periodicity=False,
arrangement="conservative"):
super().__init__(leftright_periodicity, topbottom_periodicity)
self.arrangement = arrangement
def __repr__(self):
repr_OOF = "TriSkeleton(arrangement='{0}', left_right_periodicity={1}, " \
"top_bottom_periodicity={2})".format(self.arrangement,
self.leftright_periodicity,
self.topbottom_periodicity)
return repr_OOF
[docs]class FixedDict:
"https://stackoverflow.com/a/14816446/4892892"
[docs] def __init__(self, dictionary):
self._dictionary = dictionary
def __setitem__(self, key, item):
if key not in self._dictionary:
raise KeyError("The key {} is not defined.".format(key))
self._dictionary[key] = item
def __getitem__(self, key):
return self._dictionary[key]
def __repr__(self):
return self._dictionary.__repr__()
def __str__(self):
return self._dictionary.__str__()
nt = namedtuple("modules", ["image", "microstructure", "material",
"pixelgroup", "skeleton"])
image = FixedDict({"name": None, "extension": None, "fullname": None})
microstructure = FixedDict({"name": None, "pixelgroups": None})
material = []
# material = FixedDict({"names": [], "pixelgroups": []})
pixelgroup = {}
skeleton = FixedDict({"name": None, "geometry": None})
[docs]class OOF2:
script = []
_modules = nt._make([image, microstructure, material, pixelgroup, skeleton])
_state = FixedDict({"image_read": False, "microstructure_created": False,
"groups_created": False, "material_created": False,
"pixelgroups_created": False, "skeleton_created": False,
"script_saved": False})
[docs] def read_image(self, label_image):
# TODO: check somehow if the input is a label image
filename, extension = os.path.splitext(os.path.basename(label_image))
self._modules.image["name"] = filename
self._modules.image["extension"] = extension
self._modules.image["fullname"] = filename + extension
self._state["image_read"] = True
[docs] def create_microstructure(self, name=None):
"""Creates a microstructure from an image.
Parameters
----------
name : str, optional
Path to the image on which the microstucture is created,
file extension included. If not given, the microstructure is given
the same name as the input image.
Raises
------
Exception
DESCRIPTION.
Returns
-------
None.
"""
if not self._state["image_read"]:
raise Exception("Load an image first with the `read_image` method.")
if name:
if not isinstance(name, str):
raise Exception("File name must be a string")
else:
name = self._modules.image["name"]
self._modules.microstructure["name"] = name
self.script.append("OOF.Microstructure.Create_From_ImageFile"
"(filename='{0}', microstructure_name='{1}', "
"height=automatic, width=automatic)"
.format(self._modules.image["fullname"],
self._modules.microstructure["name"]))
self._state["microstructure_created"] = True
[docs] def pixel2group(self):
self.script.append("OOF.Image.AutoGroup(image='{0}', name_template='%n')"
.format(self._modules.microstructure["name"] + ":" +
self._modules.image["fullname"]))
self._state["groups_created"] = True
[docs] def save_microstructure(self, name=None):
if not self._state["microstructure_created"]:
raise Exception("Create the mictrostructure first with the "
"`create_microstructure` method.")
if name:
if not isinstance(name, str):
raise Exception("File name must be a string")
else:
name = self._modules.microstructure["name"] + '.txt'
self.script.append("OOF.File.Save.Microstructure(filename='{0}', "
"mode='w', format='script', microstructure='{1}')"
.format(name, self._modules.microstructure["name"]))
[docs] def load_pixelgroups(self, microstructure_file):
"""
Parameters
----------
microstructure_file : str
DESCRIPTION.
Returns
-------
None.
"""
if self._state["pixelgroups_created"]:
raise Exception("Pixelgroups already created.")
# TODO: other option is to overwrite the existing pixel group.
# However, in this case, all subsequent steps (e.g. materials2groups)
# need to be cancelled.
# Identify which pixel belongs to which category
with open(microstructure_file, 'r') as microstructure:
data = microstructure.readlines()
category = []; group = []
for line in data:
if "OOF.LoadData.Microstructure.DefineCategory.PixelGroups" in line:
m = re.match(".+category=([\w]+),\sgroups=\['([\w]+)'\]", line)
category.append(int(m.group(1)))
group.append(int(m.group(2)))
elif "OOF.LoadData.Microstructure.Categories" in line:
m = re.match(r".+categories=(.+)\)", line)
nestedlist = eval(m.group(1))
pixelcategory = np.array(nestedlist)
# Obtain the pixel-group classification using the category-group relation
pixelgroup = pixelcategory.copy()
for i in range(len(category)):
pixelgroup[pixelcategory == category[i]] = group[i]
self._modules.microstructure["pixelgroups"] = pixelgroup
self._modules.pixelgroup.update(dict.fromkeys(group))
self._state["pixelgroups_created"] = True
[docs] def save_pixelgroups(self, name=None):
"""
Parameters
----------
name : str
DESCRIPTION.
Returns
-------
None.
"""
if name:
if not isinstance(name, str):
raise Exception("File name must be a string")
else:
name = self._modules.image["name"]
np.save(name, self._modules.microstructure["pixelgroups"])
[docs] def create_material(self, name):
"""
Parameters
----------
name : TYPE
DESCRIPTION.
Raises
------
Exception
DESCRIPTION.
Returns
-------
None.
"""
if name in self._modules.material:
raise Exception("Material `{0}` already exists. Give another name."
.format(name))
self._modules.material.append(name)
self.script.append("OOF.Material.New(name='{0}', material_type='bulk')"
.format(name))
self._state["material_created"] = True
[docs] def materials2groups(self, materials, groups=None):
"""
Parameters
----------
materials : list of str
DESCRIPTION.
groups : list of int, optional
DESCRIPTION. The default is None.
Returns
-------
None.
"""
if groups:
if len(materials) == len(groups):
for mat, gr in zip(materials, groups):
if mat in self._modules.material:
self.script.append("OOF.Material.Assign(material='{0}', "
"microstructure='{1}', pixels='{2}')"
.format(mat, self._modules.microstructure["name"], gr))
self._modules.pixelgroup[gr] = mat
# self._modules.material[mat] = gr
else:
raise Exception("Material `{0}` does not exist.".format(mat))
else:
raise Exception("The number of materials and the number of groups must agree.")
else:
n_material = len(materials)
if n_material == 1:
mat = materials[0]
if mat in self._modules.material:
# Associate the material to all the pixel groups
for gr in self._modules.pixelgroup:
self.script.append("OOF.Material.Assign(material='{0}', "
"microstructure='{1}', pixels='{2}')"
.format(mat, self._modules.microstructure["name"], gr))
self._modules.pixelgroup[gr] = mat
else:
raise Exception("Material `{0}` does not exists.".format(mat))
else: # must give groups to avoid ambiguity
raise Exception("{0} number of groups expected.".format(n_material))
[docs] def create_skeleton(self, nelem_x, nelem_y, geometry, name=None):
if not self._state["microstructure_created"]:
raise Exception("Create the mictrostructure first with the "
"`create_microstructure` method.")
if name:
if not isinstance(name, str):
raise Exception("File name must be a string")
else:
name = self._modules.image["name"]
self._modules.skeleton["name"] = name
self.script.append("OOF.Skeleton.New(name='{0}', microstructure='{1}', "
"x_elements={2}, y_elements={3}, "
"skeleton_geometry={4})"
.format(self._modules.skeleton["name"],
self._modules.microstructure["name"],
nelem_x, nelem_y, repr(geometry)))
self._state["skeleton_created"] = True
[docs] def write_script(self, name=None):
if name:
if not isinstance(name, str):
raise Exception("File name must be a string")
else:
name = self._modules.image["name"] + ".script"
with open(name, 'w') as script:
script.writelines("\n".join(self.script))
self._state["script_saved"] = True
[docs] def show(self):
"""
Returns
-------
None.
"""
print("\n".join(self.script))
def __str__(self):
"""Customizes how the object is printed.
Displays basic information about the materials.
For detailed information, use the `show` method.
Returns
-------
str
DESCRIPTION.
"""
# display = ''.join(display)
# return display
return ""