Skip to content

Commit a69b73b

Browse files
committed
Added pre-defined sets for faces, edges and vertices of RVE
1 parent fe5eece commit a69b73b

File tree

4 files changed

+194
-9
lines changed

4 files changed

+194
-9
lines changed

src/kanapy/api.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ def write_abq(self, nodes=None, file=None, path='./', voxel_dict=None, grain_dic
765765
units=units, gb_area=faces,
766766
dual_phase=dual_phase,
767767
ialloy=ialloy, grain_phase_dict=grpd,
768-
thermal=thermal)
768+
thermal=thermal, periodic=self.rve.periodic)
769769
# if orientation exists and ialloy is defined also write material file with Euler angles
770770
if not (self.mesh.grain_ori_dict is None or ialloy is None):
771771
writeAbaqusMat(ialloy, self.mesh.grain_ori_dict,

src/kanapy/initializations.py

+129
Original file line numberDiff line numberDiff line change
@@ -611,3 +611,132 @@ def set_stats(grains, ar=None, omega=None, deq_min=None, deq_max=None,
611611
json.dump(ms_stats, outfile, indent=2)
612612

613613
return ms_stats
614+
615+
616+
class NodeSets(object):
617+
def __init__(self, nodes):
618+
self.F0yz = [] # left nodes
619+
self.F1yz = [] # right nodes
620+
self.Fx0z = [] # bottom nodes
621+
self.Fx1z = [] # top nodes
622+
self.Fxy0 = [] # rear nodes
623+
self.Fxy1 = [] # front nodes
624+
self.surfSet = [] # nodes on any surface
625+
maxX = max(nodes[:, 0])
626+
minX = min(nodes[:, 0])
627+
maxY = max(nodes[:, 1])
628+
minY = min(nodes[:, 1])
629+
maxZ = max(nodes[:, 2])
630+
minZ = min(nodes[:, 2])
631+
# select all nodes on a surface and assign to face
632+
for i, coord in enumerate(nodes):
633+
surface = False
634+
if np.isclose(coord[0], maxX):
635+
surface = True
636+
self.F1yz.append(i)
637+
if np.isclose(coord[0], minX):
638+
surface = True
639+
self.F0yz.append(i)
640+
if np.isclose(coord[1], maxY):
641+
surface = True
642+
self.Fx1z.append(i)
643+
if np.isclose(coord[1], minY):
644+
surface = True
645+
self.Fx0z.append(i)
646+
if np.isclose(coord[2], maxZ):
647+
surface = True
648+
self.Fxy1.append(i)
649+
if np.isclose(coord[2], minZ):
650+
surface = True
651+
self.Fxy0.append(i)
652+
if surface:
653+
self.surfSet.append(i)
654+
655+
# Find edges
656+
# top front edge
657+
E_T1 = np.intersect1d(self.Fxy1, self.Fx1z)
658+
self.Ex11 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 0], E_T1)
659+
# top back edge
660+
E_T3 = np.intersect1d(self.Fxy0, self.Fx1z)
661+
self.Ex10 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 0], E_T3)
662+
# top left edge
663+
E_T4 = np.intersect1d(self.F0yz, self.Fx1z)
664+
self.E01z = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 2], E_T4)
665+
# top right edge
666+
E_T2 = np.intersect1d(self.F1yz, self.Fx1z)
667+
self.E11z = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 2], E_T2)
668+
# bottom front edge
669+
E_B1 = np.intersect1d(self.Fxy1, self.Fx0z)
670+
self.Ex01 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 0], E_B1)
671+
# bottom back edge
672+
E_B3 = np.intersect1d(self.Fxy0, self.Fx0z)
673+
self.Ex00 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 0], E_B3)
674+
# bottom left edge
675+
E_B4 = np.intersect1d(self.F0yz, self.Fx0z)
676+
self.E00z = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 2], E_B4)
677+
# bottom right edge
678+
E_B2 = np.intersect1d(self.F1yz, self.Fx0z)
679+
self.E10z = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 2], E_B2)
680+
# left front edge
681+
E_M1 = np.intersect1d(self.F0yz, self.Fxy1)
682+
self.E0y1 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 1], E_M1)
683+
# right front edge
684+
E_M2 = np.intersect1d(self.Fxy1, self.F1yz)
685+
self.E1y1 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 1], E_M2)
686+
# left rear edge
687+
E_M4 = np.intersect1d(self.Fxy0, self.F0yz)
688+
self.E0y0 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 1], E_M4)
689+
# right rear edge
690+
E_M3 = np.intersect1d(self.Fxy0, self.F1yz)
691+
self.E1y0 = self.CreatePeriodicEdgeSets(self.surfSet, nodes[self.surfSet, 1], E_M3)
692+
693+
# find VERTICES
694+
self.V001 = np.intersect1d(self.Ex01, self.E00z)[0] # V1
695+
self.V101 = np.intersect1d(self.Ex01, self.E10z)[0] # V2
696+
self.V000 = np.intersect1d(self.Ex00, self.E00z)[0] # H1
697+
self.V100 = np.intersect1d(self.E10z, self.Ex00)[0] # H2
698+
self.V111 = np.intersect1d(self.Ex11, self.E11z)[0] # V3
699+
self.V110 = np.intersect1d(self.E11z, self.Ex10)[0] # H3
700+
self.V011 = np.intersect1d(self.Ex11, self.E01z)[0] # V4
701+
self.V010 = np.intersect1d(self.Ex10, self.E01z)[0] # H4
702+
703+
# CORNERNODES = [self.V000, self.V100, self.V010, self.V001, self.V011, self.V101, self.V110, self.V111]
704+
705+
def CreatePeriodicNodeSets(self, Nodes, sortCoord1, sortCoord2, NodeSet):
706+
# Creates a List of Sorted Nodes with respect to sortCoord1 and sortCoord2 for faces
707+
# Input: Nodeset of surface nodes
708+
import operator
709+
startList = []
710+
sortedList = []
711+
for number in NodeSet:
712+
startList.append([number, sortCoord1[Nodes.index(number)], sortCoord2[Nodes.index(number)]])
713+
startList.sort(key=operator.itemgetter(1, 2))
714+
for item in range(len(startList)):
715+
sortedList.append(startList[item][0])
716+
717+
return sortedList
718+
719+
720+
def CreatePeriodicEdgeSets(self, Nodes, sortCoord, NodeSet):
721+
# Creates a List of Sorted Nodes with respect to sortCoord for edges
722+
import operator
723+
startList = []
724+
sortedList = []
725+
for number in NodeSet:
726+
startList.append([number, sortCoord[Nodes.index(number)]])
727+
startList.sort(key=operator.itemgetter(1))
728+
for item in range(len(startList)):
729+
sortedList.append(startList[item][0])
730+
731+
return sortedList
732+
733+
def RemoveItemInList(self, NodeList, ReplaceNodeList):
734+
# remove set of nodes from list
735+
for item in ReplaceNodeList:
736+
try:
737+
NodeList.remove(item)
738+
except ValueError:
739+
pass
740+
741+
return NodeList
742+

src/kanapy/input_output.py

+61-6
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def read_dump(file):
120120

121121
def export2abaqus(nodes, file, grain_dict, voxel_dict, units='mm',
122122
gb_area=None, dual_phase=False, thermal=False,
123-
ialloy=None, grain_phase_dict=None):
123+
ialloy=None, grain_phase_dict=None, periodic=False):
124124
r"""
125125
Creates an ABAQUS input file with microstructure morphology information
126126
in the form of nodes, elements and element sets. If "dual_phase" is true,
@@ -134,19 +134,27 @@ def export2abaqus(nodes, file, grain_dict, voxel_dict, units='mm',
134134
.. note:: The nodal coordinates are written out in units of 1 mm or 1 :math:`\mu` m scale, as requested by the
135135
user in the input file.
136136
"""
137+
from kanapy.initializations import NodeSets
138+
139+
def write_node_set(name, nset):
140+
f.write(name)
141+
for i, val in enumerate(nset[:-1], start=1):
142+
if i % 16 == 0:
143+
f.write(f'{val+1}\n')
144+
else:
145+
f.write(f'{val+1}, ')
146+
f.write(f'{nset[-1]+1}\n')
137147

138148
def write_grain_sets():
139149
# Create element sets for grains
140150
for k, v in grain_dict.items():
141151
f.write('*ELSET, ELSET=GRAIN{0}_SET\n'.format(k))
142-
for enum, el in enumerate(v, 1):
152+
for enum, el in enumerate(v[:-2], start=1):
143153
if enum % 16 != 0:
144-
if enum == len(v):
145-
f.write('%d\n' % el)
146-
else:
147-
f.write('%d, ' % el)
154+
f.write('%d, ' % el)
148155
else:
149156
f.write('%d\n' % el)
157+
f.write('%d\n' % v[-1])
150158
# Create sections
151159
for k in grain_dict.keys():
152160
if grain_phase_dict is None or grain_phase_dict[k] < nall:
@@ -207,6 +215,9 @@ def write_phase_sets():
207215
else:
208216
raise ValueError(f'Units must be either "mm" or "um", not "{0}"'
209217
.format(units))
218+
nsets = NodeSets(nodes)
219+
if periodic:
220+
p_eqs = None
210221

211222
with open(file, 'w') as f:
212223
f.write('** Input file generated by kanapy\n')
@@ -275,6 +286,49 @@ def write_phase_sets():
275286
f.write('**\n')
276287
f.write('*Instance, name=PART-1-1, part=PART-1\n')
277288
f.write('*End Instance\n')
289+
f.write('**\n')
290+
f.write('** DEFINE NODE SETS\n')
291+
f.write('** 1. VERTICES\n')
292+
f.write(f'*Nset, nset=V000, instance=PART-1-1\n')
293+
f.write(f'{nsets.V000+1}\n')
294+
f.write(f'*Nset, nset=V001, instance=PART-1-1\n')
295+
f.write(f'{nsets.V001+1}\n')
296+
f.write(f'*Nset, nset=V010, instance=PART-1-1\n')
297+
f.write(f'{nsets.V010+1}\n')
298+
f.write(f'*Nset, nset=V100, instance=PART-1-1\n')
299+
f.write(f'{nsets.V100+1}\n')
300+
f.write(f'*Nset, nset=V011, instance=PART-1-1\n')
301+
f.write(f'{nsets.V011+1}\n')
302+
f.write(f'*Nset, nset=V101, instance=PART-1-1\n')
303+
f.write(f'{nsets.V101+1}\n')
304+
f.write(f'*Nset, nset=V110, instance=PART-1-1\n')
305+
f.write(f'{nsets.V110+1}\n')
306+
f.write(f'*Nset, nset=V111, instance=PART-1-1\n')
307+
f.write(f'{nsets.V111+1}\n')
308+
f.write('*Nset, nset=Vertices, instance=PART-1-1\n')
309+
f.write(f'{nsets.V000+1}, {nsets.V100+1}, {nsets.V010+1}, {nsets.V001+1}, {nsets.V011+1}, '
310+
f'{nsets.V101+1}, {nsets.V110+1}, {nsets.V111+1}\n')
311+
f.write('** 2. EDGES\n')
312+
write_node_set('*Nset, nset=Ex00, instance=PART-1-1\n', nsets.Ex00)
313+
write_node_set('*Nset, nset=Ex01, instance=PART-1-1\n', nsets.Ex01)
314+
write_node_set('*Nset, nset=Ex10, instance=PART-1-1\n', nsets.Ex10)
315+
write_node_set('*Nset, nset=Ex11, instance=PART-1-1\n', nsets.Ex11)
316+
write_node_set('*Nset, nset=E0y0, instance=PART-1-1\n', nsets.E0y0)
317+
write_node_set('*Nset, nset=E0y1, instance=PART-1-1\n', nsets.E0y1)
318+
write_node_set('*Nset, nset=E1y0, instance=PART-1-1\n', nsets.E1y0)
319+
write_node_set('*Nset, nset=E1y1, instance=PART-1-1\n', nsets.E1y1)
320+
write_node_set('*Nset, nset=E00z, instance=PART-1-1\n', nsets.E00z)
321+
write_node_set('*Nset, nset=E01z, instance=PART-1-1\n', nsets.E01z)
322+
write_node_set('*Nset, nset=E10z, instance=PART-1-1\n', nsets.E10z)
323+
write_node_set('*Nset, nset=E11z, instance=PART-1-1\n', nsets.E11z)
324+
f.write('** 3. FACES\n')
325+
write_node_set(f'*Nset, nset=Fxy0, instance=PART-1-1\n', nsets.Fxy0)
326+
write_node_set(f'*Nset, nset=Fxy1, instance=PART-1-1\n', nsets.Fxy1)
327+
write_node_set(f'*Nset, nset=Fx0z, instance=PART-1-1\n', nsets.Fx0z)
328+
write_node_set(f'*Nset, nset=Fx1z, instance=PART-1-1\n', nsets.Fx1z)
329+
write_node_set(f'*Nset, nset=F0yz, instance=PART-1-1\n', nsets.F0yz)
330+
write_node_set(f'*Nset, nset=F1yz, instance=PART-1-1\n', nsets.F1yz)
331+
f.write('**\n')
278332
f.write('*End Assembly\n')
279333
f.write('**\n')
280334
f.write('**\n')
@@ -296,6 +350,7 @@ def write_phase_sets():
296350
f.write('**\n')
297351
f.write('*Include, input={}mat.inp\n'.format(file[0:-8]))
298352
f.write('**\n')
353+
f.write('**Include, input=REM_PART.inp\n') # prepare include for BC and step definitions
299354
print('---->DONE!\n')
300355
return
301356

tests/test_input_output.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ def test_read_dump(temp_dump):
6565

6666
def test_export_abaqus():
6767

68-
nodes = [[1., 0., 1.], [1., 0., 0.], [0., 0., 0.], [0., 0., 1.], [1., 1., 1.], [1., 1., 0.], [0., 1., 0.],
68+
nodes = np.array(
69+
[[1., 0., 1.], [1., 0., 0.], [0., 0., 0.], [0., 0., 1.], [1., 1., 1.], [1., 1., 0.], [0., 1., 0.],
6970
[0., 1., 1.], [2., 0., 1.], [2., 0., 0.], [2., 1., 1.], [2., 1., 0.], [3., 0., 1.], [3., 0., 0.],
7071
[3., 1., 1.], [3., 1., 0.], [1., 2., 1.], [1., 2., 0.], [0., 2., 0.], [0., 2., 1.], [2., 2., 1.],
7172
[2., 2., 0.], [3., 2., 1.], [3., 2., 0.], [1., 3., 1.], [1., 3., 0.], [0., 3., 0.], [0., 3., 1.],
@@ -74,7 +75,7 @@ def test_export_abaqus():
7475
[2., 2., 2.], [3., 2., 2.], [1., 3., 2.], [0., 3., 2.], [2., 3., 2.], [3., 3., 2.], [1., 0., 3.],
7576
[0., 0., 3.], [1., 1., 3.], [0., 1., 3.], [2., 0., 3.], [2., 1., 3.], [3., 0., 3.], [3., 1., 3.],
7677
[1., 2., 3.], [0., 2., 3.], [2., 2., 3.], [3., 2., 3.], [1., 3., 3.], [0., 3., 3.], [2., 3., 3.],
77-
[3., 3., 3.]]
78+
[3., 3., 3.]])
7879

7980
ed = {1: [1, 2, 3, 4, 5, 6, 7, 8], 2: [9, 10, 2, 1, 11, 12, 6, 5], 3: [13, 14, 10, 9, 15, 16, 12, 11],
8081
4: [5, 6, 7, 8, 17, 18, 19, 20], 5: [11, 12, 6, 5, 21, 22, 18, 17], 6: [15, 16, 12, 11, 23, 24, 22, 21],

0 commit comments

Comments
 (0)