! Post process bolt pretension forces for bolt group Id %load_id%
! Magnus Gustafsson EDRMedeso 2016-03-16
! Magnus Gustafsson EDRMedeso 2017-05-04  Bugfix for cyclic symmetry (unselect duplicate mesh for head and thread sections)
! Magnus Gustafsson EDRMedeso 2018-02-27  V10 R19.0 Fixed csv output of result data
! Magnus Gustafsson EDRMedeso 2020-04-16  V13 R19.2 - 2020R1 MPC184
! Magnus Gustafsson EDRMedeso 2021-05-25  V211.1 2021R1 Bugfix BoltPret shaft selection, Contact slip and normal force
! Magnus Gustafsson EDRMedeso 2021-11-24  V212.2 2021R2 Bugfix BoltPret shaft selection
! Magnus Gustafsson EDRMedeso 2022-01-11  V212.3 2021R2 Bugfix BoltPret divide by zero if no contacts are found.
! Magnus Gustafsson EDRMedeso 2022-07-01  V222.1 2022R2 Bugfix Ignore auto-assymmetric contact result with zero
! Magnus Gustafsson EDRMedeso 2022-11-28  V222.3 2022R2 Bugfix co-axial bolts #49
! Magnus Gustafsson EDRMedeso 2023-11-14  V232.4 2023R2 PostAllTimePoints #66
! Magnus Gustafsson EDRMedeso 2024-08-29  V242.1 2024R2 #84 GUI improvements
! Magnus Gustafsson EDRMedeso 2025-01-17  V2025.10 2025R1 Updated variable name to "snake_case"
! Magnus Gustafsson EDRMedeso 2025-05-05  V2025.12 2025R1 Bugfix coaxial Simplified Bolts
! Magnus Gustafsson EDRMedeso 2026-03-16  V2025.26 2025R2 Support for symmetry csys
! Magnus Gustafsson EDRMedeso 2026-06-18  V2026.11 2026R1 Improved speed looping over result sets
! Magnus Gustafsson EDRMedeso 2026-10-16  V2026.13 2026R1 Bugfix for using "Contact Split (DMP) = On"

! Input variable:
!   load_ids: array [load_id, r_slip]
!   boltdata_%load_id%
!   post_all_steps
! Fallback input variable:
!   load_id, r_slip
! Output variable:
!   boltRes_%load_id%
!   boltRes_Id%load_id%.csv

! Check if "load_ids" is defined
*get,n_loads,parm,load_ids,dim,1
*if,n_loads,eq,0,then
  ! Fallback to use "load_id" and "r_slip"
  n_loads = 1
  *dim,load_ids,array,1,2
  load_ids(1,1) = load_id
  load_ids(1,2) = r_slip
*endif
! Get number of steps
/post1
*afun,rad
file,../file,rst
inres,nsol,nload,misc
*if,post_all_steps,gt,1,then
  nsets = 1
  set,post_all_steps,1
*elseif,post_all_steps,eq,1,then
  *get,nsets,active,0,set,nset
*else
  set,last
  *get,nsets,active,0,set,lstp
*endif
! Loop over all bolt objects to store components and variables
*do,ll,1,n_loads
  load_id = load_ids(ll,1)
  r_slip = load_ids(ll,2)
  n_bolts = nbolts_%load_id%
  *dim,boltRes_%load_id%,array,n_bolts,16,nsets
  *get,boltdata_col,parm,boltdata_%load_id%,dim,2
  ! Loop over all bolts in bolt group
  *do,kk,1,n_bolts
    pret_node = boltdata_%load_id%(kk,1)
    X1 = boltdata_%load_id%(kk,2)
    Y1 = boltdata_%load_id%(kk,3)
    Z1 = boltdata_%load_id%(kk,4)
    NX = boltdata_%load_id%(kk,5)
    NY = boltdata_%load_id%(kk,6)
    NZ = boltdata_%load_id%(kk,7)
    bolt_real = boltdata_%load_id%(kk,11)
    pret_elem = boltdata_%load_id%(kk,12)
    pret_ename = boltdata_%load_id%(kk,13)
    ! Define WP aligned with bolt pretension normal
    *if,boltdata_col,gt,15,then
      X2 = boltdata_%load_id%(kk,16)
      Y2 = boltdata_%load_id%(kk,17)
      Z2 = boltdata_%load_id%(kk,18)
      X3 = boltdata_%load_id%(kk,19)
      Y3 = boltdata_%load_id%(kk,20)
      Z3 = boltdata_%load_id%(kk,21)
    *else
      X2 = X1 + NX
      Y2 = Y1 + NY
      Z2 = Z1 + NZ
      X3 = X1 + 0.5*(NX+NZ)
      Y3 = Y1 + 0.5*(NX+NY)
      Z3 = Z1 + 0.5*(NZ+NY)
    *endif
    wplane,,X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3
    wprota,,,90
    csys,4
    ! Get pretension location
    *if,pret_ename,eq,179,then
      nsel,s,node,,pret_node
      esln
      nsle
      nsel,u,node,,pret_node
      *get,z0,node,,mnloc,z
      cm,pret_nodes,node   ! Pretension nodes in bolt shaft
      esel,inve
      esln,r
    *else
      esel,s,elem,,pret_elem
      *get,z0,elem,pret_elem,cent,z
      nsle
      esln,s,1
      *get,e_count,elem,,count
      *if,e_count,eq,1,then  ! Beam bolt
        esel,inve
        esln,r
      *else
        esel,u,elem,,pret_elem
        e_pilot1 = elnext(0)
        e_pilot2 = elnext(e_pilot1)
        *get,e_real1,elem,e_pilot1,attr,real
        *get,e_real2,elem,e_pilot2,attr,real
        esel,s,real,,e_real1
        esel,a,real,,e_real2
        esel,r,ename,,174
        nsle
        esln
        esel,u,ename,,174
      *endif
    *endif
    *get,e_count,elem,,count
    cm,shaft_elems,elem  ! Bolt shaft elements selected
    ! Select one side of bolt shaft
    *if,pret_ename,eq,179,then
      *if,e_count,gt,2,then
        nsel,u,node,,1,pret_node
        esln,r
        *get,e_count1,elem,,count
        esel,r,cent,z,z0,1e6
        *get,e_count2,elem,,count
        *if,e_count1,ne,e_count2,then
          cmsel,s,pret_nodes
          cmsel,s,shaft_elems
          nsel,r,node,,1,pret_node
          esln,r
        *endif
      *else
        esel,r,cent,z,z0,1e6
        nsle,r
      *endif
      cm,n_shaft_%load_id%_%kk%,node
      cm,e_shaft_%load_id%_%kk%,elem
    *endif
    ! Find all slip contacts around bolt
    cswpla,11,1
    *if,e_count,gt,2,then
      esel,s,real,,bolt_real
      esel,r,cent,x,0,r_slip
    *else
      cmsel,s,shaft_elems
    *endif
    nsle
    esln
    *get,zmin,node,,mnloc,z
    *get,zmax,node,,mxloc,z
    dz = 0.01*(zmax-zmin)
    esel,inve
    esel,r,ename,,174
    esel,r,cent,x,0,r_slip
    esel,r,cent,z,zmin-dz,zmax+dz
    *get,e_count,elem,,count
    mm = 0
    *dowhile,e_count
      cm,slip_el,elem
      elmin = elnext(0)
      *get,e_real,elem,elmin,attr,real
      *get,e_secn,elem,elmin,attr,secn
      esel,s,real,,e_real
      esel,r,ename,,170
      esel,r,cent,x,0,r_slip
      *get,targ_count,elem,,count
      *if,targ_count,gt,0,then
        cmsel,s,slip_el
        esel,r,secn,,e_secn
        nsle
        *get,n_count,node,,count
        *if,n_count,gt,0,then
          mm = mm + 1
          cm,n_slip_%load_id%_%kk%_%mm%,node
          cm,e_slip_%load_id%_%kk%_%mm%,elem
        *endif
      *endif
      cmsel,s,slip_el
      esel,u,secn,,e_secn
      *get,e_count,elem,,count
    *enddo
    n_slip_%load_id%_%kk% = mm
  *enddo  ! kk Bolt index
*enddo  ! ll Load index
! Loop over all results sets
*do,nn,1,nsets
  allsel
  *if,post_all_steps,gt,1,then
    *get,nset,active,0,set,nset,first,post_all_steps
  *elseif,post_all_steps,eq,1,then
    set,,,,,,,nn
    nset = nn
  *else
    set,nn
    *get,nset,active,0,set,nset,last,nn
  *endif
  ! Loop over all bolt objects
  *do,ll,1,n_loads
    load_id = load_ids(ll,1)
    *get,boltdata_col,parm,boltdata_%load_id%,dim,2
    ! Loop over all bolts in bolt group
    *do,kk,1,nbolts_%load_id%
      pret_node = boltdata_%load_id%(kk,1)
      X1 = boltdata_%load_id%(kk,2)
      Y1 = boltdata_%load_id%(kk,3)
      Z1 = boltdata_%load_id%(kk,4)
      NX = boltdata_%load_id%(kk,5)
      NY = boltdata_%load_id%(kk,6)
      NZ = boltdata_%load_id%(kk,7)
      pret_elem = boltdata_%load_id%(kk,12)
      pret_ename = boltdata_%load_id%(kk,13)
      boltRes_%load_id%(kk,1,nn) = nset
      boltRes_%load_id%(kk,2,nn) = kk
      boltRes_%load_id%(kk,4,nn) = X1
      boltRes_%load_id%(kk,5,nn) = Y1
      boltRes_%load_id%(kk,6,nn) = Z1
      ! Define WP aligned with bolt pretension normal
      *if,boltdata_col,gt,15,then
        X2 = boltdata_%load_id%(kk,16)
        Y2 = boltdata_%load_id%(kk,17)
        Z2 = boltdata_%load_id%(kk,18)
        X3 = boltdata_%load_id%(kk,19)
        Y3 = boltdata_%load_id%(kk,20)
        Z3 = boltdata_%load_id%(kk,21)
      *else
        X2 = X1 + NX
        Y2 = Y1 + NY
        Z2 = Z1 + NZ
        X3 = X1 + 0.5*(NX+NZ)
        Y3 = Y1 + 0.5*(NX+NY)
        Z3 = Z1 + 0.5*(NZ+NY)
      *endif
      wplane,,X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3
      wprota,,,90
      ! Get pretension adjustment and bolt force
      rsys,0
      *if,pret_ename,eq,179,then
        boltRes_%load_id%(kk,3,nn) = pret_node
        nsel,s,node,,pret_node
        *get,UX1,node,pret_node,U,X
        *if,boltdata_col,gt,22,then
          beam_elem1 = boltdata_%load_id%(kk,22)
        *else
          beam_elem1 = 0
        *endif
        *if,beam_elem1,gt,0,then
          *get,FX1,elem,beam_elem1,smisc,19  ! Beam Shear Force SFy node J
          *get,FY1,elem,beam_elem1,smisc,18  ! Beam Shear Force SFz node J
          *get,FZ1,elem,beam_elem1,smisc,14  ! Beam Axial Force Fx node J
          *get,MX1,elem,beam_elem1,smisc,15  ! Beam Moment My node J
          *get,MY1,elem,beam_elem1,smisc,16  ! Beam Moment Mz node J
          *get,MZ1,elem,beam_elem1,smisc,17  ! Beam Moment TQ node J
        *else
          cmsel,s,n_shaft_%load_id%_%kk%
          cmsel,s,e_shaft_%load_id%_%kk%
          spoint,,X1,Y1,Z1   ! Point for moment summation
          rsys,4
          fsum,rsys
          *get,FX1,fsum,,item,FX
          *get,FY1,fsum,,item,FY
          *get,FZ1,fsum,,item,FZ
          *get,MX1,fsum,,item,MX
          *get,MY1,fsum,,item,MY
          *get,MZ1,fsum,,item,MZ
        *endif
      *else
        boltRes_%load_id%(kk,3,nn) = pret_elem
        esel,s,elem,,pret_elem
        *get,UX1,elem,pret_elem,smisc,63  ! JRU3 Joint relative displacement of DOF 3
        UX1 = -UX1
        *get,FX1,elem,pret_elem,smisc,1   ! Constraint Force in X direction
        *get,FY1,elem,pret_elem,smisc,2   ! Constraint Force in Y direction
        *get,FZ1,elem,pret_elem,smisc,3   ! Constraint Force in Z direction
        *get,MX1,elem,pret_elem,smisc,4   ! Constraint Moment in X direction
        *get,MY1,elem,pret_elem,smisc,5   ! Constraint Moment in Y direction
        *get,MZ1,elem,pret_elem,smisc,6   ! Constraint Moment in Z direction
      *endif
      ! Get contact slip force
      rsys,4
      Fs_avg = 0
      Fc_avg = 0
      n_skip = 0
      Fs_ang = 999
      *do,mm,1,n_slip_%load_id%_%kk%
        cmsel,s,n_slip_%load_id%_%kk%_%mm%
        cmsel,s,e_slip_%load_id%_%kk%_%mm%
        fsum,rsys,cont
        *get,FX2,fsum,,item,FX
        *get,FY2,fsum,,item,FY
        *get,FZ2,fsum,,item,FZ
        *if,abs(FZ2),eq,0,then
          n_skip = n_skip + 1
        *else
          Fs = sqrt(FX2*FX2+FY2*FY2)
          Fs_avg = Fs_avg + Fs
          Fc_avg = Fc_avg + abs(FZ2)
          *set,Fs_atan2,atan2(FY2,FX2)
          *if,Fs_ang,eq,999,then
            Fs_ang = 0
          *elseif,Fs_ang-Fs_atan2,gt,1.5708,then
            Fs_atan2 = Fs_atan2 + 3.1416
          *elseif,Fs_atan2-Fs_ang,gt,1.5708,then
            Fs_atan2 = Fs_atan2 - 3.1416
          *endif
          Fs_ang = Fs_ang + Fs_atan2
        *endif
      *enddo
      n_slip1 = n_slip_%load_id%_%kk% - n_skip
      *if,n_slip1,gt,0,then
        Fs_avg = Fs_avg/n_slip1
        Fc_avg = Fc_avg/n_slip1
        Fs_ang = Fs_ang/n_slip1
      *else
        Fs_ang = 0
      *endif
      boltRes_%load_id%(kk, 7,nn) = UX1
      boltRes_%load_id%(kk, 8,nn) = FX1
      boltRes_%load_id%(kk, 9,nn) = FY1
      boltRes_%load_id%(kk,10,nn) = FZ1
      boltRes_%load_id%(kk,11,nn) = MX1
      boltRes_%load_id%(kk,12,nn) = MY1
      boltRes_%load_id%(kk,13,nn) = MZ1
      boltRes_%load_id%(kk,14,nn) = Fs_avg
      boltRes_%load_id%(kk,15,nn) = Fc_avg
      boltRes_%load_id%(kk,16,nn) = Fs_ang
    *enddo  ! kk Bolt index
  *enddo  ! ll Load index
*enddo  ! nn load step index
! Loop over all bolt objects and output csv
*do,ll,1,n_loads
  load_id = load_ids(ll,1)
  Id = 'boltRes_%load_id%'
  *if,pret_ename,eq,179,then
    /output,boltRes_Id%load_id%,csv
    /com,Nset,Bolt Id,Pret. node,X,Y,Z,Adjust,FX,FY,FZ,MX,MY,MZ,Fs_avg,Fc_avg,Fs_ang
    /output
  *else
    /output,boltRes_Id%load_id%,csv
    /com,Nset,Bolt Id,Pret. elem,X,Y,Z,Adjust,FX,FY,FZ,MX,MY,MZ,Fs_avg,Fc_avg,Fs_ang
    /output
  *endif
  *cfopen,boltRes_Id%load_id%,csv,,append
  *do,nn,1,nsets
    *vwrite,%Id%(1,1,nn),%Id%(1,2,nn),%Id%(1,3,nn),%Id%(1,4,nn),%Id%(1,5,nn),%Id%(1,6,nn),%Id%(1,7,nn),%Id%(1,8,nn),%Id%(1,9,nn),%Id%(1,10,nn),%Id%(1,11,nn),%Id%(1,12,nn),%Id%(1,13,nn),%Id%(1,14,nn),%Id%(1,15,nn),%Id%(1,16,nn)
    (F6.0',',F8.0',',F12.0',',12(E14.6','),E14.6)
  *enddo
  *cfclos
*enddo
alls
