import numpy as np
[docs]
class parameter_sweep():
"""
This is a core UPXO class. Use to generate and work with multiple mcgs
using a combination of various generating and controlling parameters.
Targetted at:
-------------
* research: understanding algorithm sensitivity
* research: understanding parameter sensitivity
* research: understanding grain growth evolution
* development: UPXO
Data structures:
----------------
* Each PXTAl object is stored in a DICT under the instance number key.
* Most properties are stored as Pandas dataframes.
* The user input parameters are preserved under self.uiAAAAA,
where, AAAAA is the additional name string of the corresponsing
parameter set.
* Mesh instances are stored seperately as a DICT under the instance
number key, followed by a nested DICT under the mcstep key.
Data attributes:
----------------
domain: Size of the domain
dim: dimensionality
gmp: global morphological parameters
qmp: Q-partitioned morphological parameters
purge_previous: Purge previous study objects
save_sims: BOOL: flag to pickle raw databases of simulations
__GENLOCK__: str: flag to lock simulation capability of UPXO
__GENLOCK__:
------------
If 'locked', no simulations will be performed and grain structures
will not be developed. Otherwise, if 'open'. Status set to 'locked'
whenever following cases:
* when user input validation fails.
* when computations branch towards any lock imposed by developer
in UPXO internals.
"""
__slots__ = ('N', 'nstates', 'domain', 'dim',
'algo_hop', 'algo_hops',
'purge_previous', '_save_sims_',
'gsi',
'gmp', 'qmp',
'mesh_instances',
)
__paramater_gsi_mapping_behaviour__ = 'one-many'
__default_mcalg__ = '200'
# ------------------------------------------------------------------
'''
NOTE: @ all locks :: Locked if True, Open if False
__GS_GEN_LOCK__: GS generation lock.
__GR_IDNT_LOCK__: Grain identification lock
__GSMORPH_CHAR_LOCK__: Morphology characterisation lock
__GS_ANALYSIS_LOCK__: Grain structure analysis lock
__TEX_SAM_LOCK__: Texture sampling lock
__TEX_MAP_LOCK__: Texture mapping lock
__FE_GEN_LOCK__: Finite element mesh generation lock
__FE_EXP_LOCK__: Finite element mesh export lock
__REP_QUAL_LOCK__: Representativeness qualification lock
__FERES_MAP_LOCK__: Finite element result map lock
__FERES_ANALYSIS_LOCK__: Finite element result analysis lock
'''
__GS_GEN_LOCK__, __GR_IDNT_LOCK__ = [True, True], [True, True]
__GSMORPH_CHAR_LOCK__, __GS_ANALYSIS_LOCK__ = [True, True], [True, True]
__TEX_SAM_LOCK__, __TEX_MAP_LOCK__ = [True, True], [True, True]
__FE_GEN_LOCK__, __FE_EXP_LOCK__ = [True, True], [True, True]
__REP_QUAL_LOCK__ = [True, True]
__FERES_MAP_LOCK__, __FERES_ANALYSIS_LOCK__ = [True, True], [True, True]
# ------------------------------------------------------------------
__GS_GEN_LOCK__ = [{'uigrid_type': True, 'uigrid_range': True,
'uisim_type': True, 'uisim_range': True,
'uigsc_type': True, 'uigsc_range': True,
'uimesh_type': True, 'uimesh_range': True,
'uigeomrepr_type': True, 'uigeomrepr_range': True, },
{'uigrid_type': True, 'uigrid_range': True,
'uisim_type': True, 'uisim_range': True,
'uigsc_type': True, 'uigsc_range': True,
'uimesh_type': True, 'uimesh_range': True,
'uigeomrepr_type': True, 'uigeomrepr_range': True, },
]
# ------------------------------------------------------------------
def __init__(self,
use_default_values=False,
study='gs_analysis'):
"""
Instantiates parameter sweep data-structure and perform user
requested tasks
Parameters
----------
use_default_values : BOOL, optional
If True, data-structure will be instantiated with default values
for parameters of grid, simulation, grain structure analysis,
meshing, geometric representations, etc. The default is False.
If False, empty data-structure will be created. In which case,
the user will have to seperately use the set_param_{ABCD} methods.
study : srt, optional
- If 'gs_analysis': All functionalities necessary for
gs_analysis shall remain unlocked by default. All higher
functionalities remain locked by default.
- If 'gs_mesh': All functionalities necessary for grain
structure meshing including the mesh export remain uncloked by
default.
- If 'gs_growth': All functionalities necessary for grain growth
study remain unlocked by default.
- If 'cpfe_data_analysis': All functionalities necessary for
gs_analysis remain unlocked by default.
- If '_development_': All functionalities necessary for
gs_analysis remain unlocked by default.
NOTE-1:
User input validity may change the corrsponding sub-lock
states.
NOTE-2:
Available options are contained in dth.opt.ps_studies
Returns
-------
None.
"""
# Initiate gsi=None to enable __repr__ when not assign_default_values.
__gsi_index__ = None
if use_default_values:
self.initialize(N=2)
# ----------------------------------------------------------------
self.set_param_grid(domain_size=((0, 100),
(0, 100),
(0, 0),
1),
read_from_file=False,
filename=None)
for i, _ in enumerate(self.N):
a = self.gsi[i].uisim.__uigrid_type_lock__
b = self.gsi[i].uisim.__uigrid_range_lock__
self.__GS_GEN_LOCK__[i]['uigrid_type'] = a
self.__GS_GEN_LOCK__[i]['uigrid_range'] = b
# ----------------------------------------------------------------
self.set_param_sim(mcsteps=20,
nstates=32,
solver='python',
tgrad=None,
algo_hop=False,
algo_hops=[(200, 10),
(201, 40),
(202, 100)],
default_mcalg=self.default_mcalg,
save_at_mcsteps=np.linspace(0, 20, 5),
purge_previous=False,
read_from_file=False,
filename=None)
self.set_param_gsc(char_grains=True,
char_stage='postsim',
library='scikit-image',
parallel=True,
find_gbseg=True,
g_area=True,
gb_length=True,
ofton=True,
gb_njp_order=True,
g_eq_dia=True,
g_feq_dia=True,
g_solidity=True,
g_circularity=True,
g_mjaxis=True,
g_mnaxis=True,
g_morph_ori=True,
g_el=True,
g_ecc=True,
read_from_file=False,
filename=None)
self.set_param_geomrepr(make_mp_grain_centoids=True,
make_mp_grain_points=True,
make_ring_grain_boundaries=True,
make_xtal_grain=True,
make_chull_grain=True,
create_gbz=[False, True],
gbz_thickness=[0.1, 0.2],
read_from_file=False,
filename=None)
self.set_param_mesh(generate_mesh=False,
target_fe_software='abaqus',
par_treatment='global',
mesher='upxo',
gb_conformities=('conformal',
'non_conformal',
),
global_elsizes=(0.5,
1.0,
),
mesh_algos=(4,
6,
),
grain_internal_el_gradient=('constant',
'constant',
),
grain_internal_el_gradient_par=(('automin',
'automax'),
('automin',
'automax'),
),
target_eltypes=('CSP4',
'CSP8',
),
elsets=('grains',
'grains',
),
nsets=('x-', 'x+', 'y-', 'y+', ),
optimize=(False,
False,
),
opt_par=('min_angle',
[45, 60],
'jacobian',
[0.45, 0.6],
),
read_from_file=False,
filename=None)
def __repr__(self):
"""Return a string representation of this instance."""
print('/'*60)
print("+ + + + + UPXO MCGS PARAMETER SWEEP + + + + +")
print('/'*60)
print(f"Number of parameter datasets: {len(self.N)}")
print('/'*60)
for n in self.N:
self.info_attributes(n)
if n != self.N[-1]:
print('= '*30)
print('/'*60)
return ''
@property
def info_message_display_level(self):
"""Info message display level."""
return [self.gsi[n].info_message_display_level for n in self.N]
@info_message_display_level.setter
def info_message_display_level(self, level):
"""Info message display level."""
if level == 'simple':
self.set_gsi_info_message_display_level_simple
elif level == 'detailed':
self.set_gsi_info_message_display_level_detailed
@property
def info_message_display_level_simple(self):
"""Info message display level simple."""
for n in self.N:
self.gsi[n].info_message_display_level_simple
@property
def info_message_display_level_detailed(self):
"""Info message display level detailed."""
for n in self.N:
self.gsi[n].info_message_display_level_detailed
def __iter__(self):
"""Return an iterator over this instance."""
self.__gsi_index__ = 1
return self
def __next__(self):
"""Return the next item from this iterator."""
if self.__gsi_index__ <= len(self.N):
_gsi_ = self.gsi[self.__gsi_index__]
self.__gsi_index__ += 1
return _gsi_
else:
raise StopIteration
[docs]
def limit_check(self):
"""Limit check."""
raise NotImplementedError("limit_check is not yet implemented.")
[docs]
def generate_mcgs2d(self):
"""Generate mcgs2d."""
raise NotImplementedError("generate_mcgs2d is not yet implemented.")
[docs]
def characterize_gs(self):
"""Characterize gs."""
raise NotImplementedError("characterize_gs is not yet implemented.")
[docs]
def initialize(self, N=2):
"""Initialize."""
if type(N) == int and N != 0 and N < 25:
self.N = [n+1 for n in range(N)]
from mcgs import monte_carlo_grain_structure as mcgs
self.gsi = {}
for n in range(N):
self.gsi[n+1] = mcgs(study='para_sweep')
else:
print(f'Invalid N: {N}. None initialized. Skipped')
[docs]
def run(self,
char_post_sim=True,
parallel_char=False,
):
'''
Sweeps across pipelines to achieve as per user request, across
all allowed and possible combination of individual and sets of
various parameters. Will only be consideref if defaults is True.
The default is False.
char_post_sim:
Characterize during sims or post sims
parallel_char:
Parallelise characterization.
Only if char_post_sim=True
If parchar=False, characterization GS will not be characterized,
in which case, use the characterize method explicitly.
'''
raise NotImplementedError("run is not yet implemented.")
[docs]
def assemble_locks(self):
"""Assemble locks."""
for n in self.N:
self.__GENLOCK__['uisim'] = self.gsi[n].uisim.__uisim_lock__
[docs]
def set_param_grid(self,
domain_size=((0, 100), (0, 100), (0, 0), 1),
read_from_file=False,
filename=None
):
"""
Set up the parameters pertaining to grid. Targetted at
ps.gsi[:].uigrid
Parameters
----------
domain_size : list/tuple/deque/np.ndarray, optional
((x bounds), (y bounds), (z bounds), pixel size or increment).
A bound is specified by two values, minimum and maximum. First
value MUST be the numerically lower number. As no checks are made
to validate this user entry, user must take care to enter these
values.
NOTE: pixel size will be uniform across x, y and z axes.
The default is ((0, 100), (0, 100), (0, 0), 1).
Returns
-------
None.
"""
for n in self.N:
self.gsi[n].set_uigrid(domain_size,
read_from_file=False,
filename=None
)
[docs]
def set_param_sim(self,
mcsteps=20,
nstates=32,
solver='python',
tgrad=None,
algo_hop=False,
default_mcalg='200',
algo_hops=[(200, 10), (201, 40), (202, 100)],
save_at_mcsteps=np.linspace(0, 20, 5),
state_sampling_scheme='rejection',
consider_boltzmann_probability=False,
s_boltz_prob='q_related',
boltzmann_temp_factor_max=0.1,
boundary_condition_type='wrapped',
NL=1,
kineticity='static',
purge_previous=False,
read_from_file=False,
filename=None
):
"""
Explanation
-----------
This is part of parameter setting methods for
parameter sweep studies. Helps set grain structure simulation
parameters like. The followig parameters are set by set_param_sim:
* mcsteps
* nstates
* solver
* tgrad
* algo_hop
* algo_hops
* save_at_mcsteps
* purge_previous
Usage
-----
UPXO internal and user. Will be used if the user prefers quick
parameter sweep with default values. If user, user wishes to have
specirfic values, which would be most often the case.
Parameters
----------
mcsteps : int, optional
Number of Monte-Carlo steps. To restrict comparisons over
different temporal scales, all grain structure instances will
be simulated upto equal mcsteps.
NOTE: However, if in a case, the grain structure temporally
saturates during simulation before the total mcsteps for that
specific gsi is reaced, then the total number of mcsteps actyually
covered would be smaller than that specified by the user. This is
becvause, all core-solver algorithms in UPXO are designed to
STOP when the grain structure reaces temporal saturation. This
saturation happens when there is a single grain in the GS, that
is all state values in the gs lattice become same.
The default is 20.
nstates : int, optional
The total number of unique state values in the simulation. A value
of 2 would basically generate an Ising type lattice.
The default is 32.
solver : str, optional
Specifies whether the solver is to be from python or C. The choice
depens on the following parameters:
* Size of the spatial domain
* Total number of mcsteps
* Computational cost of the algorithm
The decision between 'python' and 'c' should happen based on
simulation domain largness, which depend on the largeness of the
spatial domain, largeness of the temporal dimension and finally
largeness of the computational cost.
Input is case-independent.
Choosing 'C' will force UPXO to use
the C-executatable for core solver. This option is only ava8ilable
fo0r some algorithms. To know supported algorithms, please refer
to info on algorithms.
Choosing 'python' will make UPXO to decide between 'python' and
'c', based on practicality of using 'python' for large simulation
domains.
The default option is 'python'
tgrad : np.ndarray, optional
Temperature gradient field of size. Size same as that of grid of
lattice or that of the state value matrix. Each lattice point must
accompanied by a temperature value.
The default is None.
algo_hop : bool/str, optional
This helps decide whether to use a single algorithm for the
entire temporal domain or whether you would need UPXO
to hop across algorithms.
If False: disallow algorithm hopping
If True: allow algorithm hopping
If str: only allowed value as of now is 'auto'.
If 'auto': UPXO will decide which algorithms to use upon need of
a algorithm hopping.
The default is False.
algo_hops : list/str/int, optional
1. If options pertaining to algorithm hopping has
been provided by the user, then the first available
option pertaining to algorithm ID will be used to
set the algorithm. For example, if algo_hops is
[(200, 10), (201, 40), (202, 100)], then mcalg will be
set to '200'.
2. If a numerical entry has been made (in a case where the
user has done through direct access through set_param_sim),
then if it is valid, then str(value) will be set for mcalg.
If invalid, mcalg will default to '200' for each hop.
3. If a string entry has been made (in a case where the
user has done through direct access through set_param_sim),
then if it is valid, then it will be set for mcalg.
If invalid, mcalg will default to '200'
The default is [(200, 10), (201, 40), (202, 100)], meaning:
algo200, upto 10% sim time
algo201, upto 40% sim time
algo202, upto 100% sim time
save_at_mcsteps : ITERABLE, optional
DESCRIPTION. The default is np.linspace(0, 20, 5).
Returns
-------
None.
"""
for n in self.N:
sim_parameters = {'mcsteps': mcsteps,
'nstates': nstates,
'solver': solver,
'tgrad': tgrad,
'default_mcalg': default_mcalg,
'algo_hop': algo_hop,
'algo_hops': algo_hops,
'save_at_mcsteps': save_at_mcsteps,
'state_sampling_scheme': state_sampling_scheme,
'consider_boltzmann_probability': consider_boltzmann_probability,
's_boltz_prob': s_boltz_prob,
'boltzmann_temp_factor_max': boltzmann_temp_factor_max,
'boundary_condition_type': boundary_condition_type,
'NL': NL,
'kineticity': kineticity,
'purge_previous': purge_previous,
}
self.gsi[n].set_uisim(n=n,
sim_parameters=sim_parameters,
read_from_file=False,
filename=None
)
[docs]
def set_param_gsc(self,
char_grains=True, char_stage='postsim',
library='scikit-image', parallel=True,
find_gbseg=True, g_area=True, gb_length=True,
gb_length_crofton=True, gb_njp_order=True,
g_eq_dia=True, g_feq_dia=True, g_solidity=True,
g_circularity=True, g_mjaxis=True, g_mnaxis=True,
g_morph_ori=True, g_el=True, g_ecc=True,
read_from_file=False, filename=None
):
"""
Set flags for grain structure characterisaiton and analysis.
Parameters
----------
char_grains : bool, optional
Flag to charatcterize grains. If True, grains will be
characterised and not if False. If True, grain boundaries will also
be characterised for basic properties. Once the grains have been
identifies, the characterisation will be done using scikit-image
by default, at this version of UPXO.
The default is False.
char_stage : str, optional
Choose when to characterize the grains. Options include:
* 'postsim'
* 'insim'
If 'postsim', grain structure will be characterised after all
temporal slices have been extracted i.e. after all monte-carlo
iterations have been completed. If 'insim', grain structure
will be charactersed at the end of each monte-carlo iteration.
The default is 'postsim'.
library : str, optional
Choose which library to identifying the grains. Options include:
* scikit-image: 2D and 3D
* opencv: 2D only
* upxo: 2d only (deprecated)
The default is 'scikit-image'.
parallel : bool, optional
Decides whether grain structure characterisation should be done
using parallel execution. Following combinations of options are
permitted:
* If True and char_stage is 'post_sim', then grain structyure
characterisation will be done with parallel computation.
* If True and char_stage is 'in-sim', then the combination is
invalid. The grain characterisaion will be done at the end of
each mc iteration.
* If False and char_stage is 'post_sim', then grain structure
characterisation will done after all mc iterations are
completed, but one temporal slice after the other. However,
the calculation of individual morphological parameters will
be done using pooling when possible. When this option is not
possible, behaviour will be similar to that of the combination
False and 'in-sim'.
* If False and char_stage is 'in-sim', then grain structure
characterisation will be carried out at the end of each
mc iteration. No part of the process will be threaded or
pooled or executed in parallel.
The default is False.
find_gbseg : bool, optional
Flag to identify the grain boundary segments. If True, the grain
boundary segments will be identified and not if False. GB segments
will be identified by UPXO and no other oprtion is needed.
The following behaviours should be kept in mind:
* Will only work if char_grains is True. Assuming it is True,
the following further points hold.
* If find_gbseg is False, but gb_njp_order is True, then, the
grain boundary segments will still be identified to allow the
calculation of njp order.
The default is False.
g_area : bool, optional
Flag to calculate grain area. The calculaion takes into
consideration, the pixel area of the underlying grid. The default
is False.
gb_length : bool, optional
Falg to calculate the grain boundary length. The calculation takjes
into considertation, side length of the pixel of the underlying
grid. The following behaviour should be noted:
* If char_grains is False, and gb_length is True, then
grain boundary lengths will not be calculated.
* if grain boundary segments have been identified and gb_length
is True, then along with calculating grain boundary lengths,
the lengths of gerain boundaryu segments will also be
calculated.
The default is False.
gb_length_crofton : bool, optional
Flag to calculate the Crofton perimeter of the grain boundary.
For more information, please refer to: https://scikit-image.org/
docs/stable/auto_examples/segmentation/plot_perimeters.html
The default is False.
gb_njp_order : bool, optional
Flag to calculate the 'n' of junction points, that is the value of
grain boundary junction point order. Its value is the number of
grains a grain boundary junction point is being shared with. If 3,
we have a triple point junction, if 4, we have a quadruple point
junction and so on.
The following behaviours must be noted:
* Will only be calculated if char_grains is True and grain
boundary segments have been identified.
The default is True.
g_eq_dia : bool, optional
Flag to calculate the equivalent diameter of the grain. If True,
equiavelnt diamater of the grains will be caclculated, not if
False. The following behaviours must be noted:
* If grain_area is False, and g_eq_dia is True, then the
grain area will still be calculated to allow claculation
of grain equivalent diameter. However, only the grain
equivalent diameter will be saved as an attribute and not the
grain area, which was not requested.
* Equiavalent diameter caluclation will consider the area
of the pixel in the grid. Infact, it gets carried from the
grain_area claculation.
The default is True.
g_feq_dia : bool, optional
Flag to calculate the Feret equivalent diameter. If True, the
Feret equivalent will be calculated, not if False. Behaviours
are similar to that of g_eq_dia.
The default is True.
g_solidity : bool, optional
Flag to calculate the solidity of grain. The default is True.
g_circularity : bool, optional
Flag to calculate grain circularity. The default is True.
g_mjaxis : bool, optional
Flag to calculate the major axis of the grain. The default is True.
g_mnaxis : bool, optional
Flag to calculate the ninor axis of the grain. The default is True.
g_morph_ori : bool, optional
Flag to calculate the morphological orientation of the grains.
Bounded in [-90, 90] degrees. The default is True.
g_el : TYPE, optional
DESCRIPTION. The default is True.
g_ecc : bool, optional
Flag to calculate the eccentricity of the grains. The default is
True.
Returns
-------
None.
"""
for n in self.N:
self.gsi[n].set_uigsc(char_grains=char_grains,
char_stage=char_stage,
library=library, parallel=parallel,
find_gbseg=find_gbseg,
g_area=g_area, gb_length=gb_length,
gb_length_crofton=gb_length_crofton,
gb_njp_order=gb_njp_order,
g_eq_dia=g_eq_dia, g_feq_dia=g_feq_dia,
g_solidity=g_solidity,
g_circularity=g_circularity,
g_mjaxis=g_mjaxis, g_mnaxis=g_mnaxis,
g_morph_ori=g_morph_ori, g_el=g_el,
g_ecc=g_ecc, read_from_file=read_from_file,
filename=filename
)
[docs]
def set_param_geomrepr(self,
make_mp_grain_centoids=True,
make_mp_grain_points=True,
make_ring_grain_boundaries=True,
make_xtal_grain=True, make_chull_grain=True,
create_gbz=True, gbz_thickness = 0.1,
read_from_file=False, filename=None
):
"""
Set parametwers needed to generate geometrical representations of the
Monte-Carlo Grain Structure.
Parameters
----------
make_mp_grain_centoids : bool, optional
Make UPXO multi-point object grom the grain centroids
The default is True.
make_mp_grain_points : bool, optional
Make multi-point objects of all pixel cenrtoids in grains.
NOTE: Not recommended for large domains.
The default is False.
make_ring_grain_boundaries : bool, optional
Make UPXO multi-point object from all points on the grain boundary
of a grains. Number of objects made will equal to the number
of grains. The default is True.
make_xtal_grain : bool, optional
Make UPXO XTAL object for the grain. The default is True.
make_chull_grain : bool, optional
Flag to create convex hull object of the grain.
The default is True.
create_gbz : bool, optional
Flag to create grain boundary zone. This operation will also make
the grain core zone. Both of these will be available to be
turned into element sets for FE mesh export.
The default is True.
gbz_thickness : float/int, optional
Control the thickness of the grain boundary zone. Value must be
between 0 and 1 and is the fraction of actual grain boundary
thickness in grid units to minor axis length of the grain.
NOTE: For grains, where grain boundary zones cannot be created
due to morphological restrictions, data for the speciric grain
will be kept at None. Default value is 0.1.
Returns
-------
None.
"""
for n in self.N:
self.gsi[n].set_uigeomrepr(make_mp_grain_centoids=make_mp_grain_centoids,
make_mp_grain_points=make_mp_grain_points,
make_ring_grain_boundaries=make_ring_grain_boundaries,
make_xtal_grain=make_xtal_grain,
make_chull_grain=make_chull_grain,
create_gbz=create_gbz,
gbz_thickness=gbz_thickness,
read_from_file=read_from_file,
filename=filename)
[docs]
def set_param_mesh(self, generate_mesh=False, target_fe_software='abaqus',
par_treatment='global', mesher='upxo',
gb_conformities=('conformal', 'non_conformal'),
global_elsizes=(0.5, 1.0), mesh_algos=(4, 6),
grain_internal_el_gradient=('constant', 'constant'),
grain_internal_el_gradient_par=(('automin', 'automax'),
('automin', 'automax'),
),
target_eltypes=('CSP4', 'CSP8'),
elsets=('grains', 'grains'),
nsets=('x-', 'x+', 'y-', 'y+', ),
optimize=(False, False),
opt_par=('min_angle', [45, 60],
'jacobian', [0.45, 0.6]),
read_from_file=False, filename=None
):
"""
Set the meshing parameters for parameter sweep studies
Parameters
----------
generate_mesh : BOOL, optional
Flag to mesh the grain structure.
The default is False.
target_fe_software : STR, optional
The FE software for which the mesh is targetted at.
Current options include 'abaqus'.
Future options shall be 'moose', 'damask'
The default is 'abaqus'.
par_treatment : STR, optional
Specifies whether some (see below list) are to apply for
all instances in the parameter sweep dataset, OR, whether,
a unique parameter is to be used for a unique instance. This
applies for the following user input parameters:
* gb_conformities
* global_elsizes
* mesh_algos
* grain_internal_el_gradient
* target_eltypes
* optimize
If 'local', then 'n' values for each of the above parameters
must be provided. 'n' is the number of parameter sweeps, which is
len(ps.N).
The default is 'global'.
mesher : STR, optional
Specify the mesher. Options are 'upxo', 'pygmsh', 'gmsh', 'abaqus'
-'upxo': applies only to pizellated mesh (non-conformal) of the 2D,
3D MCGS.
-'pygmsh', 'gmsh': Applies to geometrised 2D MCGS, 3D MCGS, 2D VTGS
and 3D VTGS
-'abaqus': applies to 2D VTGS and geometrised 2D MCGS
This will write data to disk. UPXO-ABAQUS python scripts are then
to be used to construct and mesh the grain structure in ABAQUS
The default is 'upxo'.
gb_conformities : MIXED: STR/ITERABLE, optional
Individual value options: 'conformal', 'non_conformal'
If STR and 'conformal', then all instances will conformally meshed.
if STR and 'non_conformal', then all instances will non-conformally
meshed.
if ITERABLE and of the right size, then each instance will be
meshed as per the value in the location in gb_conformities
corresponding to the instance.
if ITERABLE and of the wrong size, parameter sweep study stops.
The default is ('conformal', 'non_conformal').
global_elsizes : MIXED: FLOAT/ITERABLE, optional
If FLOAT, then it will be mapped to all instances
If ITERABLE and of the right size, then each instance will be
meshed with the corresponding element size.
If ITERABLE and of the wrong size, then parameter sweep study
stops.
The default is (0.5, 1.0).
mesh_algos : MIXED: INT/ITERABLE, optional
If INT, then it will be mapped to all instances
If ITERABLE and of the right size, then each instance will be
meshed with the corresponding specified algirithm
If ITERABLE and of the wrong size, then parameter sweep
study will stop.
The default is (4, 6).
grain_internal_el_gradient : MIXED: STR/ITERABLE, optional
If STR, then all instances will be meshed
with the same element gradient specification
If ITERABLE and of the right size, then all instances will be
meshed using correpsoning values of element gradients
If ITERABLE and of the wrong size, then parameter sweep study
stops.
Options are 'constant', 'linear_gb_to_centroid',
'linear_centroid_to_gb', 'linear_gb_to_core', 'linear_core_to_gb'
- For value other than 'constant', then global_elsizes will not
be used. Instead values provided by grain_internal_el_gradient_par
will be used.
- For value 'linear_gb_to_centroid', min size will be near gb and
max size will be at centroid. Variation will be linear.
- For value 'linear_centroid_to_gb', max size will be near gb and
min size will be at centroid. Variation will be linear.
- For value 'linear_gb_to_core', min size will be near gb and
size increases linearly towards the max size along vectors
normal to the local gb edge. Vector will be directed towards
inner region of the grain.
- For value 'linear_core_to_gb', max size will be near gb and
size decreases linearly towards the min size along vectors
normal to the local gb edge. Vector will be directed towards
inner region of the grain
The default is ('constant', 'constant').
grain_internal_el_gradient_par : MIXED: ITERABLE(STR/FLOAT)/ITERABLE,
optional.
If STR/FLOAT, same action will be mapped onto all instances.
If (STR, STR), only allowed non-interchangeable values is 'automin'
and 'automax'. If ('automin', 'automax'), then element sizes
will be calculated using a combination of grain boundary
properties, maximum intercept along the curve normal, grain
shape factor, etc. The procedure is described in theoretical
manual.
If (FLOAT, FLOAT), then values will be chosen accordingly and
maps accordingly to all instances.
NOTE @ dev: RETAIN THIS TO BE ('automin', 'automax') and not
replace with just 'auto', for reason of conformity to a standard
user data specification format.
The default is (('automin', 'automax'),).
target_eltypes : MIXED: STR/ITERABLE, optional
If STR, value is correct and allowed, then same element types
will be mapped to all instances.
If ITERABLE, all values are STR, correct and allowed, then values
get mapped to each instance seperately and accordingly.
The default is ('CSP4', 'CSP8').
elsets : MIXED: STR/ITERABLE, optional
If STR, valid and allowed, the resuested elment set will be
mapped to all instances.
If ITERABLE, values are STR, valid and allowed, then values will
be mapped to corresponding instances.
The default is ('grains', 'grains').
nsets : ITERABLE, optional
Nodal sets to make. Used to impose boundary conditions.
Options: 'x-', 'x+', 'y-', 'y+', 'gb', 'rp_random_none_10'
- Option 'gb': grain boundary nodes. A 'gn' nodal set will be
created for each grain. Naming will be based on parent grain name.
- Option 'rp_random_10': representative points, 10 in number.
These points are points fully inside the grain. None of these
points would lie on the grain boundary of the grain. 'random'
denotes random positioning of representative points. Following
'none' indicates completely randomised. If in place of 'none', we
have a number (INT/FLOAT), then this number specifies the minimum
distance of seperation between all representative points inside
the grain. The following number 10, necessiates that there should
be 10 coordinate positions (as ITERABLES), if 'random' locationing.
If these input data-format rules are not conformed to, then
parameter sweep study stops.
The default is ('x-', 'x+', 'y-', 'y+', ).
optimize : MIXED: BOOL/ITERABLE, optional
If BOOL, then this optimization flag will be mapped to all
instances.
If ITERABLE and of right size, then each optimization flag will be
mapped to each instance accordingly.
If ITERABLE and of wrong size, then parameter sweep study will
stop.
Options: True, False
The default is (False, False).
opt_par : MIXED: STR/ITERABLE, optional
Specifies the element quality metric to optimize the mesh for.
The default is ('min_angle', [40, 60], 'jacobian', [0.45, 0.6])
'min_angle' is the minimum angle in the distribution of
minimum angles of all finite elements. [40, 60] denotes the
bounds of acceptance. Note that if objectives are not met,
UPXO will enable recursive mesh refinement near places
where these minimum angle falls outside the specified bounds.
'jacobian': similar explanations apply.
Returns
-------
None.
"""
for n in self.N:
self.gsi[n].set_uimesh(generate_mesh=generate_mesh,
target_fe_software=target_fe_software,
par_treatment=par_treatment,
mesher=mesher,
gb_conformities=gb_conformities,
global_elsizes=global_elsizes,
mesh_algos=mesh_algos,
grain_internal_el_gradient=grain_internal_el_gradient,
grain_internal_el_gradient_par=grain_internal_el_gradient_par,
target_eltypes=target_eltypes,
elsets=elsets, nsets=nsets,
optimize=optimize, opt_par=opt_par,
read_from_file=read_from_file,
filename=filename
)
[docs]
def save(self):
'''
Pickle the dataset
'''
raise NotImplementedError("save is not yet implemented.")
[docs]
def update_gmp(self):
"""Set or update te gmp."""
raise NotImplementedError("update_gmp is not yet implemented.")
[docs]
def update_qmp(self):
"""Set or update te qmp."""
raise NotImplementedError("update_qmp is not yet implemented.")
[docs]
def plot(self,
defaults=False,
docformat='pdf',
xax='time',
yax='area',
zax='sim',
xaxpar='',
yaxpar='',
zaxpar='',
plot_type='best',
):
'''
if defaults=True:
It generates a set of plots to enable getting a quick
overview of the data. Plots will be exported to a
PDF [ref 1].
Following plots are made.
* Grain structure plots of the final MC step of all sims.
* Grain size evolution for all sims.
[ref 1]: Currently, only PDF is supported. It is planned to enable
writing data to MS Word, MS PPT, Google Doc, Google presentation,
MS Excel and Google Spreadsheet.
--------------------------------------------------
xax: x-axis
Options: time, alg, temperature
yax: y-axis
Options: time, {morph. parameter}
zax: z-axis
Options:
xaxpar: Parameter for the x-axis
yaxpar: Parameter for the y-axis
zaxpar: Parameter for the z-axis
NOTE:
if all in (xaxpar, yaxpar, zaxpar) is provided,
UPXO will override xax, yax, zax
--------------------------------------------------
plot_type: Type of visualization
--------------------------------------------------
'''
raise NotImplementedError("plot is not yet implemented.")
@property
def uigrid(self):
"""
This is an imitation method. It imitates the instantiated class
which makes uigrid attribute. Imitation is of the 1st grain
structure instance. The reason for making an imitation is:
* All grain structure instances WILL have grids having the
same dimensionality, bounds and increments.
* Hence, it is not needed to make a seperate grid availabale
to the paramater sweep object.
* Instead, when this property method is called, it just
returns the uigrid of the first grain structure isntance, if
it exists.
* No big deal here.
NOTE: This documentation applies also to uisim, uigsc, uimesh,
uigeomrepr
"""
_ = None
if hasattr(self, 'gsi'):
if self.gsi and type(self.gsi) == dict and len(self.gsi) >= 1:
if hasattr(self.gsi[1], 'uigrid'):
print('ps.uigrid:: taken from: ps.gsi[1].uigrid')
_ = self.gsi[1].uigrid
else:
print('ps.gsi[1].uigrid has not been set. Skipped.')
else:
print('Invalid ps.gsi. Skipped.')
else:
print('ps.gsi has not been set. Skipped.')
return _
@property
def uisim(self):
"""
This is an imitation method. Refer to ps.uigrid for more documentation.
"""
_ = None
if hasattr(self, 'gsi'):
if self.gsi and type(self.gsi) == dict and len(self.gsi) >= 1:
if hasattr(self.gsi[1], 'uisim'):
print('ps.uisim:: taken from: ps.gsi[1].uisim')
_ = self.gsi[1].uisim
else:
print('ps.gsi[1].uisim has not been set. Skipped.')
else:
print('Invalid ps.gsi. Skipped.')
else:
print('ps.gsi has not been set. Skipped.')
return _
@property
def uigsc(self):
"""
This is an imitation method. Refer to ps.uigrid for more documentation.
"""
_ = None
if hasattr(self, 'gsi'):
if self.gsi and type(self.gsi) == dict and len(self.gsi) >= 1:
if hasattr(self.gsi[1], 'uigsc'):
print('ps.uigsc:: taken from: ps.gsi[1].uigsc')
_ = self.gsi[1].uigsc
else:
print('ps.gsi[1].uigsc has not been set. Skipped.')
else:
print('Invalid ps.gsi. Skipped.')
else:
print('ps.gsi has not been set. Skipped.')
return _
@property
def uimesh(self):
"""
This is an imitation method. Refer to ps.uigrid for more documentation.
"""
_ = None
if hasattr(self, 'gsi'):
if self.gsi and type(self.gsi) == dict and len(self.gsi) >= 1:
if hasattr(self.gsi[1], 'uimesh'):
print('ps.uimesh:: taken from: ps.gsi[1].uimesh')
_ = self.gsi[1].uimesh
else:
print('ps.gsi[1].uimesh has not been set. Skipped.')
else:
print('Invalid ps.gsi. Skipped.')
else:
print('ps.gsi has not been set. Skipped.')
return _
@property
def uigeomrepr(self):
"""
This is an imitation method. Refer to ps.uigrid for more documentation.
"""
_ = None
if hasattr(self, 'gsi'):
if self.gsi and type(self.gsi) == dict and len(self.gsi) >= 1:
if hasattr(self.gsi[1], 'uigeomrepr'):
print('ps.uigeomrepr:: taken from: ps.gsi[1].uigeomrepr')
_ = self.gsi[1].uigeomrepr
else:
print('ps.gsi[1].uigeomrepr has not been set. Skipped.')
else:
print('Invalid ps.gsi. Skipped.')
else:
print('ps.gsi has not been set. Skipped.')
return _
[docs]
def info_attributes(self, n, throw=False):
"""Info attributes."""
if n not in self.N:
print('N not set. Skipped')
else:
str1 = f"~~~ Parameter sweep dataset: {n} ~~~"
print(str1 + '\n')
# ----------------------------------------------------------------
str2 = "(A. GRID):: mc simulation grid: "
_ = ' '*12
if hasattr(self.gsi[n], 'uigrid'):
str2 += f"{self.gsi[n].uigrid.dim}D."
str2 += f"{ self.gsi[n].uigrid.type[:2]}."
strxa = f" x:({self.gsi[n].uigrid.xmin}"
strxb = f",{self.gsi[n].uigrid.xmax}"
strxc = f",{self.gsi[n].uigrid.xinc})"
strx = strxa + strxb + strxc
strya = f" y:({self.gsi[n].uigrid.ymin}"
stryb = f",{self.gsi[n].uigrid.ymax}"
stryc = f",{self.gsi[n].uigrid.yinc})"
stry = strya + stryb + stryc
if self.gsi[n].uigrid.dim == 2:
str2 += strx + stry
elif self.gsi[n].uigrid.dim == 3:
strza = f" z:({self.gsi[n].uigrid.zmin}"
strzb = f",{self.gsi[n].uigrid.zmax}"
strzc = f",{self.gsi[n].uigrid.zinc})"
strz = strza + strzb + strzc
str2 += strx + stry + strz
else:
str2 += '\n' + _
str2 += "Grid parameters not set.\n"
str2 += _ + "Use set_param_grid(..)"
print(str2)
# ----------------------------------------------------------------
str3 = "(B: SIMPAR):: mc simulation: "
_ = ' '*14
if hasattr(self.gsi[n], 'uisim'):
str3 += f"{self.gsi[n].uisim.mcsteps}"
str3 += f" SOLVER: {self.gsi[n].uisim.solver}"
if len(self.gsi[n].uisim.save_at_mcsteps) > 2:
_0 = self.gsi[n].uisim.save_at_mcsteps[0]
_1 = self.gsi[n].uisim.save_at_mcsteps[1]
str3 += ' IN-SIM SAVES: every ' + str(int(_1 - _0))
str3 += ' mcsteps'
else:
str3 += ' IN-SIM SAVES at 0 mcstep'
else:
str3 += '\n' + _
str3 += "Simulation parameters not set.\n"
str3 += _ + "Use set_param_sim(..)"
print(str3)
# ----------------------------------------------------------------
str4 = "(C: GSCPAR):: gs characterisation: "
_ = ' '*14
if hasattr(self.gsi[n], 'uigsc'):
str4 += f"{self.gsi[n].uigsc.char_grains} \n"
if self.gsi[n].uigsc.char_grains:
str4 += _ + "CHARACTERIZATION STAGE: "
str4 += f"{self.gsi[n].uigsc.char_stage}\n"
str4 += _ + "PARALLEL CHARACTERIZATION: "
str4 += f"{self.gsi[n].uigsc.parallel}"
else:
str4 += '\n' + _
str4 += 'Grain str. characterisation parameters not set.\n'
str4 += ' '*14 + "Use set_param_uigsc(..)"
print(str4)
# ----------------------------------------------------------------
str5 = "(D: MESHPAR):: fe mesh: "
_ = ' '*15
if hasattr(self.gsi[n], 'uimesh'):
str5 += f"{self.gsi[n].uimesh.generate_mesh}"
if self.gsi[n].uimesh.generate_mesh:
str5 += "\n" + _
str5 += "TARGET SOFTWARE: "
str5 += f"{self.gsi[n].uimesh.target_fe_software}\n"
str5 += _ + "PARAMETER TREATMENT: "
str5 += f"{self.gsi[n].uimesh.par_treatment}\n"
str5 += _ + "MESHER: {self.gsi[n].uimesh.mesher}\n"
str5 += _ + "GB CONFORMITIES: Use: "
str5 += f"{self.gsi[n].uimesh.gb_conformities}\n"
str5 += _ + "GLOBAL ELEMENT SIZES: Use: "
str5 += "ps.gsi[n].uimesh.global_elsizes\n"
str5 += _ + "MESH ALGORITHMS: Use: "
str5 += "ps.gsi[n].uimesh.mesh_algos\n"
str5 += _ + "GRAIN INTERNAL ELEMENT GRADIENT "
str5 += "SPECIFICATION: Use:"
str5 += "ps.gsi[n].uimesh.grain_internal_el_gradient\n"
str5 += _ + "GRAIN INTERNAL ELEMENT GRADIENT VALUES: "
str5 += f"{self.gsi[n].uimesh.grain_internal_el_gradient_par}\n"
str5 += _ + "ELMENT TARGET TYPES: Use: "
str5 += f"{self.gsi[n].uimesh.target_eltypes}\n"
str5 += _ + "ELEMENT SETS: Use: "
str5 += f"{self.gsi[n].uimesh.elsets}\n"
str5 += _ + "NODAL SETS: "
str5 += f"Use: {self.gsi[n].uimesh.nsets}\n"
str5 += _ + "OPTIMIZE MESH: Use: "
str5 += f"{self.gsi[n].uimesh.optimize}\n"
str5 += _ + "MESH OPTIMIZATION PARAMETERS: Use: "
str5 += f"{self.gsi[n].uimesh.opt_par}\n"
else:
str5 += '\n' + _
str5 += 'FE Mesh parameters not set.\n'
str5 += _ + "Use set_param_uimesh(..)"
print(str5)
# ----------------------------------------------------------------
str6 = "(E: GEOMREPR):: PXTAL geometric repr(s).: "
_ = ' '*16
if hasattr(self.gsi[n], 'uigeomrepr'):
str6 += "MAKE MULPOINT OF GRAIN CENTROIDS: "
str6 += f"{self.gsi[n].uigeomrepr.make_mp_grain_centoids}\n"
str6 += _ + "MAKE MULPOINT OF GRAIN POINTS: "
str6 += f"{self.gsi[n].uigeomrepr.make_mp_grain_points}\n"
str6 += _ + "MAKE RING OBJECTS OF GRAIN BOUNDARIES: "
str6 += f"{self.gsi[n].uigeomrepr.make_ring_grain_boundaries}\n"
str6 += _ + "MAKE XTAL OBJECTS OF GRAINS: "
str6 += f"{self.gsi[n].uigeomrepr.make_xtal_grain}\n"
str6 += _ + "MAKE CONVEX HULL OBJECTS OF GRAINS: "
str6 += f"{self.gsi[n].uigeomrepr.make_chull_grain}\n"
str6 += _ + "MAKE GRAIN BOUNDARY ZONE: "
str6 += f"{self.gsi[n].uigeomrepr.create_gbz}\n"
str6 += _ + "MAKE 2D.VTGS PXTAL FROM GRAIN CENTROIDS: "
str6 += "Use: PS.gsi[n].uigeomrepr.make_2dvtgs"
else:
str6 += 'Geoemtric repr. parameters not set.\n'
str6 += _ + "Use set_param_uigeomrepr(..)"
print(str6)
# ----------------------------------------------------------------
[docs]
def generate_report(self,
docformat='pdf'):
"""
Parameters
----------
docformat : TYPE, optional
DESCRIPTION. The default is 'pdf'.
Returns
-------
None.
"""
raise NotImplementedError("generate_report is not yet implemented.")
[docs]
def to_excel(self):
"""Export or convert to excel."""
raise NotImplementedError("to_excel is not yet implemented.")
[docs]
def model(self):
"""Model."""
raise NotImplementedError("model is not yet implemented.")
@property
def default_mcalg(self):
"""Default mcalg."""
return self.__default_mcalg__