Hello,
I’m currently trying to convert Abaqus additive manufacturing simulations into CalculiX. Everything worked out great except for the dynamic addition and removal of elements. I looked in the CCX manual and tried implementing *Model Change but it didn’t work.
To give more details on the problem I’m trying to solve, here is a small example scenario.
As outlined in the above example, I want to remove layers (elements) in the first step and subsequently add each layer in the following steps. When I implemented this in CalculiX, element removal in Step 1 functions correctly but the addition of elements does not occur from Step 2 onward.
My question here is, Can *Model Change effectively handle both the addition and removal of elements as described in my example? Any insights or suggestions would be greatly appreciated!"
Thank you @jbr for your quick response. The analysis did complete without any issues but when I open the result in PrePoMax, all I can visualize are the results of bottomplate elements that are not removed in step-1. I’m not sure if this is a visualization issue in PrePoMax.
Please advice other ways of visualizing the results and I will verify if this is an issue with solver or visualization.
@jbr, Thank you for suggesting CalculiX Advanced Environment GUI. It offers all the keywords I’m looking for. It opens my input file without any issues but can not open the FRD results file. FRD file I’m trying to open is a small file but the GUI doesn’t respond and just loads forever. I will try testing with a smaller model.
you have to do a first, static dummy step, so that all nodes and element information are wrote to
the result file. Then proceed with the removal of the layers.
@febing, This did the trick. Finally, I’m able to visualize the results. Thank you!
One last question, which I have a good understanding of based on the discussion but want to confirm is: can cgx or prepomax be able to show/hide the elements based on steps with ADD and REMOVE Model Change?
For example, in abaqus, if we have add or remove (*model change) elements in a step, abaqus CAE visualization automatically shows or hides elements according to the steps.
The new model with a dummy initial step shows the results in cgx or prepomax but all the removed elements in the second step are still shown in the visualization with no results. This is not a killer, but it would be nice to have this functionality.
Interested to hear all your thoughts on this. Thank you all!
Hi Arjun,
Cgx and Prepomax are not able to disable/enable elements according to model change. I suggested that in the Prepomax discourse group, but sure there are more important topics as new features.
i have added a new option for the result converter in the calculix component for cubit. the missing nodes in the result blocks gets added with zero values and the elements to which them belong will be marked with a cell value 1 for the partial component.
with the treshold filter in paraview you can filter those elements. i’ve have used your dogbone.inp and added the dummy step and a view more steps to add all element layers.
running .inp files is quite easy. just a few lines
ccx create job name "Dogbone" filepath "/home/user/Downloads/Dogbone.inp"
ccx run job 1
ccx wait job 1
ccx result load job 1
ccx result convert job 1 partial
if you already have the .frd for the .inp you can skip the run and wait command and directly load them.
i am currently creating some examples and now i got one that fits here. the example shows how you can make use of python, custom key words and the partial option for the conversion.
#!python
from numpy import cos,sin,arccos
import numpy as np
import cubit
cubit.init()
cubit.cmd("reset")
cubit.cmd("undo off")
def check_if_enclosed(vid1,vid2):
v1 = cubit.volume(vid1)
v2 = cubit.volume(vid2)
b_box1 = v1.bounding_box()
b_box2 = v2.bounding_box()
for i in range(3):
if b_box1[i] > b_box2[i]:
return False
if b_box1[i+3] < b_box2[i+3]:
return False
return True
def split_bodies():
body_list = cubit.get_entities("body")
for b in body_list:
if cubit.is_multi_volume(b):
cubit.cmd(f"split body {b}")
return True
def parametric_circle(t,xc,yc,R):
x = xc + R*cos(t)
y = yc + R*sin(t)
return x,y
plate_x = 200
plate_y = 100
plate_z = 5
cube_x = 5
cube_y = 5
cube_z = 5
cubit.cmd("create brick x " + str(plate_x) + " y " + str(plate_y) + " z " + str(plate_z))
cubit.cmd("create brick x " + str(cube_x) + " y " + str(cube_y) + " z " + str(cube_z))
cubit.cmd("move Volume 1 location " + str(plate_x/2) + " " + str(plate_y/2) + " " + str(plate_z/2))
cubit.cmd("move Volume 2 location " + str(cube_x/2 + plate_x/3 - plate_x/8) + " " + str(plate_y/2) + " " + str(plate_z + cube_z/2))
N = 25
R = plate_y*1/3
xc = 0
yc = 0
arc_T = np.linspace(3.14159265359/2, 3.14159265359*3/2, N)
X,Y = parametric_circle(arc_T, xc, yc, R)
vid = 0
for i in range(N):
cubit.cmd("Volume 2 copy move x " + str(X[i]) + " y " + str(Y[i]) + " z " + str(0))
vid_last = vid
vid = cubit.get_last_id( "volume")
if i!=0:
cubit.cmd(f"subtract volume {vid} from volume {vid_last} keep_tool")
cubit.cmd("move Volume 2 location " + str(cube_x/2 + plate_x*2/3 - plate_x/8) + " " + str(plate_y/2) + " " + str(plate_z + cube_z/2))
vid=0
for i in range(N):
cubit.cmd("Volume 2 copy move x " + str(X[i]) + " y " + str(Y[i]) + " z " + str(0))
vid_last = vid
vid = cubit.get_last_id( "volume")
if i!=0:
cubit.cmd(f"subtract volume {vid} from volume {vid_last} keep_tool")
vid=0
cubit.cmd("move Volume 2 location " + str(cube_x/2 + plate_x*4/5) + " " + str(plate_y/2) + " " + str(plate_z + cube_z/2))
X = np.linspace(-plate_y*1/5, plate_y*1/5, N)
Y = np.linspace(-plate_y*1/3, plate_y*1/3, N)
for i in range(N):
cubit.cmd("Volume 2 copy move x " + str(X[i]) + " y " + str(Y[i]) + " z " + str(0))
vid_last = vid
vid = cubit.get_last_id( "volume")
if i!=0:
cubit.cmd(f"subtract volume {vid} from volume {vid_last} keep_tool")
X = np.linspace(-plate_y*1/5, plate_y*1/5, N)
Y = np.linspace(plate_y*1/3, -plate_y*1/3, N)
for i in range(N):
cubit.cmd("Volume 2 copy move x " + str(X[i]) + " y " + str(Y[i]) + " z " + str(0))
vid = cubit.get_last_id("volume")
if i!=0:
overlapping_volumes = cubit.get_overlapping_volumes_at_volume(vid,cubit.get_entities("volume"))
for ov in overlapping_volumes:
if ov!=1 and ov!=2:
split_bodies()
if check_if_enclosed(vid,ov):
cubit.cmd(f"delete volume {ov}")
else:
cubit.cmd(f"subtract volume {vid} from volume {ov} keep_tool")
cubit.cmd("delete vol 2")
cubit.cmd("imprint vol all")
cubit.cmd("merge vol all")
cubit.cmd("vol all except 1 size 2.5")
cubit.cmd("vol 1 size 10")
cubit.cmd("surface all with z_coord = "+str(plate_z + cube_z)+" scheme pave")
cubit.cmd("mesh surface all with z_coord = "+ str(plate_z + cube_z))
cubit.cmd("mesh vol all except 1")
cubit.cmd("surface all in volume 1 with z_coord >= " + str(plate_z) +" scheme pave")
cubit.cmd("mesh surface all with z_coord >= "+str(plate_z))
cubit.cmd("mesh vol 1")
cubit.cmd("compress")
volume_list = cubit.get_entities("volume")
for v in volume_list:
cubit.cmd(f"block {v} add vol {v}")
cubit.cmd(f"nodeset {v} add vol {v}")
cubit.cmd(f"sideset {v} add surface all in vol 1 to {v} with is_merged = 0")
#material
cubit.cmd('create material "solid" property_group "CalculiX-FEA"')
cubit.cmd('modify material "solid" scalar_properties "CCX_ELASTIC_ISO_USE_CARD" 1')
cubit.cmd('modify material "solid" scalar_properties "CCX_PLASTIC_ISO_USE_CARD" 1')
cubit.cmd('modify material "solid" scalar_properties "CCX_DENSITY_USE_CARD" 1')
cubit.cmd('modify material "solid" matrix_property "CCX_DENSITY_DENSITY" 8 0 ')
cubit.cmd('modify material "solid" scalar_properties "CCX_SPECIFIC_HEAT_USE_CARD" 1')
cubit.cmd('modify material "solid" matrix_property "CCX_SPECIFIC_HEAT_SPECIFIC_HEAT" 420 0 ')
cubit.cmd('modify material "solid" scalar_properties "CCX_EXPANSION_ISO_USE_CARD" 1')
cubit.cmd('modify material "solid" scalar_properties "CCX_CONDUCTIVITY_USE_CARD" 1')
cubit.cmd('modify material "solid" scalar_properties "CCX_CONDUCTIVITY_ISO_USE_CARD" 1')
cubit.cmd('modify material "solid" matrix_property "CCX_CONDUCTIVITY_ISO_K_TEMPERATURE" 50 0 ')
cubit.cmd('modify material "solid" scalar_properties "CCX_ELASTIC_USE_CARD" 1')
cubit.cmd('modify material "solid" matrix_property "CCX_ELASTIC_ISO_MODULUS_VS_POISSON_VS_TEMPERATURE" 210000 0.3 0')
#section
cubit.cmd('ccx create section solid block all material 1')
#heatflux and initial temperature
volume_list = cubit.get_entities("volume")
for v in volume_list:
cubit.cmd(f"create heatflux on sideset {v} value -7.5")
#cubit.cmd(f"ccx modify heatflux {v} op new")
cubit.cmd(f"create temperature on volume {v} value 2000")
cubit.cmd(f"ccx modify temperature {v} op new")
cubit.cmd("modify temperature 1 value 100")
# field outputs
cubit.cmd('ccx create fieldoutput name "fo_node" node')
cubit.cmd('ccx modify fieldoutput 1 node frequency 1')
cubit.cmd('ccx modify fieldoutput 1 node key_on NT')
cubit.cmd('ccx modify fieldoutput 1 node key_off CP U DEPF DEPT DTF HCRI KEQ MACH MAXU MF PNT POT PRF PS PSF PT PTF PU RF RFL SEN TS TSF TT TTF TURB V VF ')
cubit.cmd('ccx create fieldoutput name "fo_element" element')
cubit.cmd('ccx modify fieldoutput 2 element frequency 1')
cubit.cmd('ccx modify fieldoutput 2 element key_on HFL')
cubit.cmd('ccx modify fieldoutput 2 element key_off CEEQ S E ECD EMFB EMFE ENER ERR HER HFLF MAXE MAXS ME PEEQ PHS SF SMID SNEG SPOS SVF SDV THE ZZS ')
# initial conditions
cubit.cmd("ccx create initialcondition temperature")
cubit.cmd(f"ccx modify initialcondition {1} temperature bc_id {1}")
cubit.cmd("ccx create step name 'dummy_step' static")
cubit.cmd("ccx step 1 add fieldoutput 1 2")
cubit.cmd("ccx create step name 'deacivate_step' static")
cubit.cmd("ccx step 2 add fieldoutput 1 2")
cubit.cmd("ccx modify step 2 parameter nlgeom_yes")
cubit.cmd("ccx create customline name 'step_2_top' after step_begin item_id 2 cline '*MODEL CHANGE,TYPE=ELEMENT,REMOVE'")
volume_list = cubit.get_entities("volume")
for v in volume_list:
if v >1:
cubit.cmd(f"ccx create customline name '{v}' after step_begin item_id 2 cline 'Block_{v}'")
cs = 2
volume_list = cubit.get_entities("volume")
for v in volume_list:
# if v > 1 and v < 3:
if v > 1:
cs = cs + 1
cubit.cmd(f"ccx create step name 'heat_{cs}' heattransfer")
cubit.cmd(f"ccx modify step {cs} heattransfer initialtimeincrement 10 timeperiodofstep 10 minimumtimeincrement 1e-5 maximumtimeincrement 10")
cubit.cmd(f"ccx step {cs} add load heatflux {v}")
cubit.cmd(f"ccx step {cs} add bc temperature {v}")
cubit.cmd(f"ccx step {cs} add fieldoutput 1 2")
cubit.cmd(f"ccx create customline name 'step_{cs}_top' after step_begin item_id {cs} cline '*MODEL CHANGE,TYPE=ELEMENT,ADD'")
cubit.cmd(f"ccx create customline name '{v}' after step_begin item_id {cs} cline 'Block_{v}'")
cs = cs + 1
cubit.cmd(f"ccx create step name 'heat_{cs}' heattransfer")
cubit.cmd(f"ccx modify step {cs} heattransfer initialtimeincrement 10 timeperiodofstep 20 minimumtimeincrement 1e-5 maximumtimeincrement 10")
cubit.cmd(f"ccx step {cs} add load heatflux {v}")
cubit.cmd(f"ccx step {cs} add fieldoutput 1 2")
cubit.cmd("ccx create job name 'model_change'")
print("ccx run job 1 no_conversion")
command = ("ccx result convert job 1 block ")
for v in volume_list:
command = command + str(v) + " "
command = command + " partial"
print(command)
PS: it is also now possible to run a job without an auto conversion after the run. and also to convert only defined blocks, nodesets and sidesets.