Skip to content

Commit 944ed07

Browse files
committed
Merge branch 'master' of github.com:ICAMS/Kanapy
2 parents 09d6d6e + c0c6cfd commit 944ed07

File tree

3 files changed

+259
-137
lines changed

3 files changed

+259
-137
lines changed

src/kanapy/core/api.py

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -721,8 +721,10 @@ def plot_slice(self, cut='xy', data=None, pos=None, fname=None,
721721
"""
722722

723723
def write_abq(self, nodes=None, file=None, path='./', voxel_dict=None, grain_dict=None,
724-
dual_phase=False, thermal=False, units=None, ialloy=None, nsdv=200, periodicBC=False,
725-
crystal_plasticity=False, phase_props=None, value=None, apply_bc=False):
724+
dual_phase=False, thermal=False, units=None, ialloy=None, nsdv=200, crystal_plasticity=False,
725+
phase_props=None,
726+
*,
727+
boundary_conditions: Optional[Dict[str, Any]] = None):
726728
"""
727729
Writes out the Abaqus deck (.inp file) for the generated RVE. The parameter nodes should be
728730
a string indicating if voxel ("v") or smoothened ("s") mesh should be written. It can also
@@ -835,9 +837,9 @@ def write_abq(self, nodes=None, file=None, path='./', voxel_dict=None, grain_dic
835837
units=units, gb_area=faces,
836838
dual_phase=dual_phase,
837839
ialloy=ialloy, grain_phase_dict=grpd,
838-
thermal=thermal, periodicBC = periodicBC,
840+
thermal=thermal,
839841
crystal_plasticity = crystal_plasticity,
840-
phase_props = phase_props, value=value, apply_bc=apply_bc)
842+
phase_props = phase_props, boundary_conditions = boundary_conditions)
841843

842844
# if orientations exist and ialloy is defined also write material file with Euler angles
843845
if not (self.mesh.grain_ori_dict is None or ialloy is None):
@@ -1579,7 +1581,7 @@ def prompt_list(field_name: str) -> List[str]:
15791581
raise ValueError(f"Missing required metadata fields: {', '.join(missing)}")
15801582

15811583
ig = {
1582-
'RVE_size': [int(v)* length_scale for v in self.rve.size],
1584+
'RVE_size': [float(v) * length_scale for v in self.rve.size],
15831585
'RVE_continuity': self.rve.periodic,
15841586
'discretization_type': 'Structured' if structured else 'Unstructured',
15851587
'discretization_unit_size': [(float(s) / float(d)) * length_scale for s, d in zip(self.rve.size, self.rve.dim)],
@@ -1741,6 +1743,21 @@ def prompt_list(field_name: str) -> List[str]:
17411743
voxel_volume = (unit_sizes[0] if len(unit_sizes) > 0 else 0.0) \
17421744
* (unit_sizes[1] if len(unit_sizes) > 1 else 0.0) \
17431745
* (unit_sizes[2] if len(unit_sizes) > 2 else 0.0)
1746+
1747+
# grid size per axis
1748+
Nx, Ny, Nz = int(rve_dim[0]), int(rve_dim[1]), int(rve_dim[2])
1749+
# infer origin from centers if available: origin = min(center) - 0.5*unit
1750+
if len(vox_center_dict) > 0:
1751+
xs = [float(c[0])* length_scale for c in vox_center_dict.values()]
1752+
ys = [float(c[1])* length_scale for c in vox_center_dict.values()]
1753+
zs = [float(c[2])* length_scale for c in vox_center_dict.values()]
1754+
ox = (min(xs) if xs else 0.0) - 0.5 * unit_sizes[0]
1755+
oy = (min(ys) if ys else 0.0) - 0.5 * unit_sizes[1]
1756+
oz = (min(zs) if zs else 0.0) - 0.5 * unit_sizes[2]
1757+
else:
1758+
ox = oy = oz = 0.0
1759+
origin = [ox, oy, oz]
1760+
17441761
# ─── precompute voxel→grain lookup ───────────────────────────────────────
17451762
voxel_to_grain = {
17461763
vid: gid
@@ -1751,7 +1768,7 @@ def prompt_list(field_name: str) -> List[str]:
17511768
grains_t0 = []
17521769
for gid in grain_phase_dict.keys():
17531770
entry = {
1754-
"gid": gid,
1771+
"grain_id": gid,
17551772
"phase_id": grain_phase_dict.get(gid),
17561773
"grain_volume": len(grain_to_voxels.get(gid, [])) * voxel_volume,
17571774
}
@@ -1762,15 +1779,36 @@ def prompt_list(field_name: str) -> List[str]:
17621779
grains_t0.append(entry)
17631780

17641781
# ─── Build time‐0 voxel dictionary ────────────────────────────────────────
1782+
def _coord_to_index_1based(c, o, d):
1783+
# i = round((c - o)/d + 0.5), robust to tiny float noise
1784+
return int(round((float(c) - float(o)) / float(d) + 0.5))
1785+
1786+
def _clamp(v, lo, hi):
1787+
return max(lo, min(hi, v))
1788+
17651789
voxels_t0 = []
17661790
for vid, gid in voxel_to_grain.items():
17671791
cx, cy, cz = vox_center_dict.get(vid, (0.0, 0.0, 0.0))
1792+
centroid = [float(cx) * length_scale,
1793+
float(cy) * length_scale,
1794+
float(cz) * length_scale]
1795+
1796+
# Compute 1-based voxel indices from centers
1797+
ix = _coord_to_index_1based(centroid[0], origin[0], unit_sizes[0])
1798+
iy = _coord_to_index_1based(centroid[1], origin[1], unit_sizes[1])
1799+
iz = _coord_to_index_1based(centroid[2], origin[2], unit_sizes[2])
1800+
1801+
# Clamp to valid range [1..N*]
1802+
ix = _clamp(ix, 1, Nx)
1803+
iy = _clamp(iy, 1, Ny)
1804+
iz = _clamp(iz, 1, Nz)
1805+
1806+
17681807
entry = {
1769-
"vid": vid,
1808+
"voxel_id": vid,
17701809
"grain_id": gid,
1771-
"centroid_coordinates": [float(cx) * length_scale,
1772-
float(cy) * length_scale,
1773-
float(cz) * length_scale],
1810+
"centroid_coordinates": centroid, # scaled for output
1811+
"voxel_index": [ix, iy, iz], # 1-based indices
17741812
"voxel_volume": voxel_volume,
17751813
}
17761814
if include_orientation:

0 commit comments

Comments
 (0)