Duplication of elements with different orientation

Jeffersondhv
Jeffersondhv Altair Community Member
edited October 2020 in Community Q&A

Hello all,

 

I'm working on a script to duplicate elements from a reference component containing a solid to a new component with the same exact solid, but in another position and orientation.

image.png.3fecf883a2fc328860c2adcafa7ffa22.png

 

The translation part was easy as the hm_getcentroid function provides the solid centroid position, so I can use the command *translatemark to translate the desired mesh to the correct position.

image.png.b714f9b1374eca63d827615eb1046212.png

 

But to match the orientation, it has been a task more difficult that I was expecting.

My approach has been to extract the moment of inertia of the reference solid and the target solid using hm_getmoiofsolid. Once I get these values, I compute the principal moment of inertia for each solid, so I have a comparable reference to use. Then I calculate the Euler parameters (or Quaternions) to obtain the rotation angles that I can use to rotate the elements from the reference solid to match the target solid orientation.

The problem I'm facing is that it seems that the inertia calculation performed by hm_getmoiofsolid seems not to be consistent, in a sense that even extracting the principal moments of inertia from them, these principal directions do not coincide with the solid orientation.

 

What could be done in this case?

 

Thanks in advance,

Jefferson Vieira

 

Answers

  • tinh
    tinh Altair Community Member
    edited November 2018

    Hi, you should use *positionmark command

  • Jeffersondhv
    Jeffersondhv Altair Community Member
    edited November 2018

    Hi, you should use *positionmark command

     

    Thanks for the answer tinh.

    I have actually already tried using *positionmark in one of my code versions, but I still get some cases where the elements end up somewhat flipped.

    I guess I might need to properly order the inertia tensor to get the correct orientation.

     

    Right now I'm using an auxiliary Python code to compute the principal moments of inertia for the solids. Is there a way to do this using Hypermesh's or TCL's functions?

     

    Thanks,

    Jefferson Vieira

  • tinh
    tinh Altair Community Member
    edited November 2018

    I think yes.

     

    Could you show the code using *positionmark? Perhaps something's wrong, it must work

  • Jeffersondhv
    Jeffersondhv Altair Community Member
    edited November 2018
  • tinh
    tinh Altair Community Member
    edited November 2018

    Your code is very long, so it is not efficient

    I see some comps are reflected, so *positionmark will not work on them (need *reflectmark to eliminate flipping)

     

     

     

     

    I think approach can be simplify based on specification of the comp:

    - it has 1 max surface

    - its max surf is irregular

     

    So we will match max surf of source comp to target ones

    To do that, we take 3 mid nodes of 3 edges of the max surf

     

     

  • tinh
    tinh Altair Community Member
    edited November 2018

    Code is like this

     proc p_GetMaxSurf {SurfList {n 1}} { 	set SaList {} 	foreach SurfId $SurfList { 		lappend SaList '$SurfId [hm_getareaofsurface surfs $SurfId]' 	} 	lrange [dict keys [join [lsort -decreasing -real -index 1 $SaList]]] 0 $n-1 } proc p_GetMaxLine {LineList {n 1}} { 	set ElList {} 	foreach EdgeId $LineList { 		lappend ElList '$EdgeId [hm_linelength $EdgeId]' 	} 	lrange [dict keys [join [lsort -decreasing -real -index 1 $ElList]]] 0 $n-1 } proc p_Mcopy args { 	*createmarkpanel comps 1 'Select source comp:' 	if {[hm_marklength comps 1]!=1} {return -code error 'Select 1 comp only'} 	set SourceComp [hm_getmark comps 1] 	*createmark elems 1 'by comp id' $SourceComp 	if {![hm_marklength elems 1]} {return -code error 'Comp #$SourceComp has no element'} 	set SourceElems [hm_getmark elems 1] 	*createmark surfs 1 'by comp id' $SourceComp 	if {![hm_marklength comps 1]} {return -code error 'Comp #$SourceComp has no surface'} 	set SourceSurfs [hm_getmark surfs 1] 	set MaxSurf [p_GetMaxSurf $SourceSurfs] 	lassign [p_GetMaxLine [join [hm_getsurfaceedges $MaxSurf]] 3] Line1 Line2 Line3 	*createmark lines 1 $Line1 	*nodecreateonlines lines 1 1 0 0 	set N1 [hm_latestentityid nodes] 	*createmark lines 1 $Line2 	*nodecreateonlines lines 1 1 0 0 	set N2 [hm_latestentityid nodes] 	*createmark lines 1 $Line3 	*nodecreateonlines lines 1 1 0 0 	set N3 [hm_latestentityid nodes] 	############################################### 	*createmarkpanel comps 1 'Select target comps:' 	hm_markremove comps 1 $SourceComp 	foreach TargetComp [hm_getmark comps 1] { 		*createmark surfs 1 'by comp id' $TargetComp 		if {[hm_marklength surfs 1]} { 			set MaxSurf [p_GetMaxSurf [hm_getmark surfs 1]] 			lassign [p_GetMaxLine [join [hm_getsurfaceedges $MaxSurf]] 3] Line1 Line2 Line3 			*createmark lines 1 $Line1 			*nodecreateonlines lines 1 1 0 0 			set N1_ [hm_latestentityid nodes] 			*createmark lines 1 $Line2 			*nodecreateonlines lines 1 1 0 0 			set N2_ [hm_latestentityid nodes] 			*createmark lines 1 $Line3 			*nodecreateonlines lines 1 1 0 0 			set N3_ [hm_latestentityid nodes] 			*currentcollector comps [hm_getcollectorname comps $TargetComp] 			eval *createmark elems 1 $SourceElems 			*duplicatemark elems 1 1 			*positionmark elems 1 $N1 $N2 $N3 $N1_ $N2_ $N3_ 		} 	} 	*clearmark all 1 }

     

  • Jeffersondhv
    Jeffersondhv Altair Community Member
    edited November 2018

    Thanks a lot. That is very helpful. I haven't thought about this approach.

     

    As I would like to have this code more general, what could be done if the max surface is regular?

     

    Thank you

  • tinh
    tinh Altair Community Member
    edited November 2018

    Hi

    In general, you have to identify an unique specification of the comp, it could be an irregular surf smaller than max surf, or 3 holes,... which forms a fundamental system. Inertial axles is such a system

    As the comp could be regular shapes like sphere, cube,... then it is simple case

  • Jeffersondhv
    Jeffersondhv Altair Community Member
    edited November 2018

    Got it.

     

    So do you know a way to compute the principal moments of inertia for the solids using TCL?

    I found that to compute eigenvalues and eigenvectors I would need to add a TCL extension, but I really don't want to use that as it would add an additional step to be able to share this code with my colleagues.

    I see that using the approaches you suggested it works for a lot of cases, but I would like to use the inertia as it would provide me a more general solution.

     

    Thanks

  • tinh
    tinh Altair Community Member
    edited November 2018

    Yes, you don't need tcllib extension package

    use templex.exe of hyperworks:

     proc p_GetPrincInertia {Ixx Iyy Izz Ixy Iyz Izx} {           set fpt [open GetEIGRL.tpl w]           puts $fpt '{eigvalreal({{$Ixx,$Ixy,$Izx},{$Ixy,$Iyy,$Iyz},{$Izx,$Iyz,$Izz}})}'           close $fpt           exec  [file join [hm_info -appinfo ALTAIR_HOME] hw bin [file tail [hm_info -appinfo HMBIN_DIR]] templex.exe] [file normalize GetEIGRL.tpl]  }

     

  • tinh
    tinh Altair Community Member
    edited November 2018

     

    You don't need eigen values but eigen vectors,

    So change eigvalreal to eigvecreal

     

     

  • tinh
    tinh Altair Community Member
    edited November 2018

    But I think using principle vectors are not as exact as using max surf

     

    code is like this

     

     proc p_GetEIGRL {Ixx Iyy Izz Ixy Iyz Izx} { 	set fpt [open GetEIGRL.tpl w] 	puts $fpt '{eigvalreal({{$Ixx,$Ixy,$Izx},{$Ixy,$Iyy,$Iyz},{$Izx,$Iyz,$Izz}})}' 	puts $fpt '{eigvecreal({{$Ixx,$Ixy,$Izx},{$Ixy,$Iyy,$Iyz},{$Izx,$Iyz,$Izz}})}' 	close $fpt 	exec [file join [hm_info -appinfo ALTAIR_HOME] hw bin [file tail [hm_info -appinfo HMBIN_DIR]] templex.exe] [file normalize GetEIGRL.tpl] } proc p_MCopy args { 	*createmarkpanel comps 1 'Select source comp:' 	if {[hm_marklength comps 1]!=1} {return -code error 'Select 1 source comp only'} 	set SourceComp [hm_getmark comps 1] 	*createmark elems 1 'by comp id' $SourceComp 	set ElemList [hm_getmark elems 1] 	if {![llength $ElemList]} {return -code error 'Not found element in comp #$SourceComp'} 	*createmark solids 1 'by comp id' $SourceComp 	set SolidId [hm_getmark solids 1] 	if {[llength $SolidId]!=1} {return -code error 'Source comp must have 1 solid'} 	set PrincInertia [string map {, ''} [eval p_GetEIGRL [hm_getmoiofsolid $SolidId]]] 	eval *createnode [hm_getcentroidofsolids 1] 	set Node1 [hm_latestentityid nodes] 	lassign $PrincInertia > > > V1 V2 V3 	*createmark nodes 1 $Node1 	*duplicatemark nodes 1 25 	set Node2 [hm_getmark nodes 1] 	eval *createvector 1 $V1 	*translatemark nodes 1 1 1 	*createmark nodes 1 $Node1 	*duplicatemark nodes 1 25 	set Node3 [hm_getmark nodes 1] 	eval *createvector 1 $V2 	*translatemark nodes 1 1 1 	*createmarkpanel comps 1 'Select target comps:' 	foreach TargetComp [hm_getmark comps 1] { 		*createmark solids 1 'by comp id' $TargetComp 		if {[hm_marklength solids 1]!=1} continue 		set PrincInertia [string map {, ''} [eval p_GetEIGRL [hm_getmoiofsolid [hm_getmark solids 1]]]] 		eval *createnode [hm_getcentroidofsolids 1] 		set Node1_ [hm_latestentityid nodes] 		lassign $PrincInertia > > > V1 V2 V3 		*createmark nodes 1 $Node1_ 		*duplicatemark nodes 1 25 		set Node2_ [hm_getmark nodes 1] 		eval *createvector 1 $V1 		*translatemark nodes 1 1 1 		*createmark nodes 1 $Node1_ 		*duplicatemark nodes 1 25 		set Node3_ [hm_getmark nodes 1] 		eval *createvector 1 $V2 		*translatemark nodes 1 1 1 		eval *createmark elems 1 $ElemList 		*currentcollector comps [hm_getcollectorname comps $TargetComp] 		*duplicatemark elems 1 1 		*positionmark elems 1 $Node1 $Node2 $Node3 $Node1_ $Node2_ $Node3_ 	} }

     

  • Jeffersondhv
    Jeffersondhv Altair Community Member
    edited December 2018

    Thank you, that's very helpful.

     

    It seems like the max surf does the job better, but I've found some cases where it does not work well.

    I'll run further tests and comment later.