BASH, Dihedral angle with four points

放肆的年华 提交于 2019-12-02 05:53:42

Based on your refined shell code elsewhere in this thread, I've transcribed that into an awk solution as well. As people seem to have found the _docd version of use, I will include that at the end. I'm also including a debug version (in the middle of the reply).

cat torsion2.awk

-

#!/bin/awk -f  
BEGIN {
  # dbg=0 # turns off dbg output
  # see below for debug version of this script
}
function acos(x)  { return atan2((1.-x^2)^0.5,x) }    
NR==1 {x1=$2; y1=$3; z1=$4}
NR==2 {x2=$2; y2=$3; z2=$4}
NR==3 {x3=$2; y3=$3; z3=$4}
NR==4 {
  x4=$2; y4=$3; z4=$4  
  # all of this code below is only executed when you read in the 4th line
  # because then you have all the data
  #
  v1x=x2-x1 ; v1y=y2-y1 ; v1z=z2-z1     #plane1
  v2x=x3-x2 ; v2y=y3-y2 ; v2z=z3-z2     #plane1
  v3x=x2-x3 ; v3y=y2-y3 ; v3z=z2-z3     #plane2
  v4x=x3-x4 ; v4y=y3-y4 ; v4z=z3-z4     #plane2

  plane1_x=(v1y*v2z)-(v1z*v2y)  # normal vector 1
  plane1_y=(v2x*v1z)-(v2z*v1x)  # normal vector 1
  plane1_z=(v1x*v2y)-(v1y*v2x)  # normal vector 1
  plane2_x=(v3y*v4z)-(v3z*v4y)  # normal vector 2
  plane2_y=(v4x*v3z)-(v4z*v3x)  # normal vector 2
  plane2_z=(v3x*v4y)-(v3y*v4x)  # normal vector 2

  v1mag=sqrt(((plane1_x)**2)+((plane1_y)**2)+((plane1_z)**2)) # magnitude normal vector 1
  v2mag=sqrt(((plane2_x)**2)+((plane2_y)**2)+((plane2_z)**2)) # magnitude normal vector 2
  vn1x=(plane1_x)/(v1mag) ; vn1y=(plane1_y)/(v1mag) ; vn1z=(plane1_z)/(v1mag) # normalization normal vector 1
  vn2x=(plane2_x)/(v2mag) ; vn2y=(plane2_y)/(v2mag) ; vn2z=(plane2_z)/(v2mag) # normalization normal vector 2

  print acos((vn1x*vn2x)+(vn1y*vn2y)+(vn1z*vn2z))*180/3.141592653589793
}

Once the file is saved, you must mark the script as executable:

chmod +x ./torsion2.awk

Then you can run it with the sample data supplied:

./torsion2.awk data.txt

The output is

58.6892

Here is the full debug version. I needed it because I had editing errors like changing y2=$3 to just y=$3! (These things happen ;-/ )

cat torsion2_debug.awk
#!/bin/awk -f

BEGIN {
  dbg=1   # turns on dbg output
  # dbg=0 # turns off dbg output
}
function acos(x)  { return atan2((1.-x^2)^0.5,x) }

NR==1 {x1=$2; y1=$3; z1=$4}
NR==2 {x2=$2; y2=$3; z2=$4}
NR==3 {x3=$2; y3=$3; z3=$4}
NR==4 {
  x4=$2; y4=$3; z4=$4

  if (dbg) {
    print "x1="x1 "\ty1="y1 "\tz1=" z1
    print "x2="x2 "\ty2="y2 "\tz2=" z2
    print "x3="x3 "\ty3="y3 "\tz3=" z3
    print "x4="x4 "\ty4="y4 "\tz4=" z4
  }

  # all of this code below is only executed when you read in the 4th line
  # because then you have all the data
  #
  v1x=x2-x1 ; v1y=y2-y1 ; v1z=z2-z1     #plane1
  v2x=x3-x2 ; v2y=y3-y2 ; v2z=z3-z2     #plane1
  v3x=x2-x3 ; v3y=y2-y3 ; v3z=z2-z3     #plane2
  v4x=x3-x4 ; v4y=y3-y4 ; v4z=z3-z4     #plane2

  if (dbg) {
    print "#dbg: v1x="v1x "\tv1y=" v1y "\tv1z="v1z
    print "#dbg: v2x="v2x "\tv2y=" v2y "\tv2z="v2z
    print "#dbg: v3x="v3x "\tv3y=" v3y "\tv3z="v3z
    print "#dbg: v4x="v4x "\tv4y=" v4y "\tv4z="v4z
  }

  plane1_x=(v1y*v2z)-(v1z*v2y)  # normal vector 1
  plane1_y=(v2x*v1z)-(v2z*v1x)  # normal vector 1
  plane1_z=(v1x*v2y)-(v1y*v2x)  # normal vector 1
  plane2_x=(v3y*v4z)-(v3z*v4y)  # normal vector 2
  plane2_y=(v4x*v3z)-(v4z*v3x)  # normal vector 2
  plane2_z=(v3x*v4y)-(v3y*v4x)  # normal vector 2
  if (dbg) {
    print "#dbg: plane1_x=" plane1_x "\tplane1_y=" plane1_y "\tplane1_z=" plane1_z
    print "#dbg: plane2_x=" plane2_x "\tplane2_y=" plane2_y "\tplane2_z=" plane2_z
  }

  v1mag=sqrt(((plane1_x)**2)+((plane1_y)**2)+((plane1_z)**2)) # magnitude normal vector 1
  v2mag=sqrt(((plane2_x)**2)+((plane2_y)**2)+((plane2_z)**2)) # magnitude normal vector 2
  if (dbg) {
    print "#dbg: v1mag=" v1mag "\tv2mag="v2mag
  }

  vn1x=(plane1_x)/(v1mag) ; vn1y=(plane1_y)/(v1mag) ; vn1z=(plane1_z)/(v1mag) # normalization normal vector 1
  vn2x=(plane2_x)/(v2mag) ; vn2y=(plane2_y)/(v2mag) ; vn2z=(plane2_z)/(v2mag) # normalization normal vector 2

  if (dbg) {
    print "#dbg: " (vn1x*vn2x) " "  (vn1y*vn2y)  " " ((vn1z*vn2z)*180/3.141592653589793)
  }
  print acos((vn1x*vn2x)+(vn1y*vn2y)+(vn1z*vn2z))*180/3.141592653589793
}

And here is the transcribed shell to awk version

I highly recommend the Grymoire's Awk Tutorial to help you understand the awk programming paradigm and its built in variables like NR (Number (of) Record).

cat torsion2_docd.awk
#!/bin/awk -f

function acos(x)  { return atan2((1.-x^2)^0.5,x) }

# x1=`awk '{print $2}' LINEA` # x1
# y1=`awk '{print $3}' LINEA` # y1
# z1=`awk '{print $4}' LINEA` # z1
# x2=`awk '{print $2}' LINEB` # x2
# y2=`awk '{print $3}' LINEB` # y2
# z2=`awk '{print $4}' LINEB` # z2
# x3=`awk '{print $2}' LINEC` # x3
# y3=`awk '{print $3}' LINEC` # y3
# z3=`awk '{print $4}' LINEC` # z3
# x4=`awk '{print $2}' LINED` # x4
# y4=`awk '{print $3}' LINED` # y4
# z4=`awk '{print $4}' LINED` # z4
NR==1 {x1=$2; y1=$3; z1=$4}
NR==2 {x2=$2; y2=$3; z2=$4}
NR==3 {x3=$2; y3=$3; z3=$4}
NR==4 {
  x4=$2; y=$3; z4=$4

  # all of this code below is only executed when you read in the 4th line
  # because then you have all the data
  #
  # v1x=`calc "($x2)-($x1)" | sed 's/^\t//g'` #plane1
  # v1y=`calc "($y2)-($y1)" | sed 's/^\t//g'` #plane1
  # v1z=`calc "($z2)-($z1)" | sed 's/^\t//g'` #plane1
  # v2x=`calc "($x3)-($x2)" | sed 's/^\t//g'` #plane1
  # v2y=`calc "($y3)-($y2)" | sed 's/^\t//g'` #plane1
  # v2z=`calc "($z3)-($z2)" | sed 's/^\t//g'` #plane1
  # v3x=`calc "($x2)-($x3)" | sed 's/^\t//g'` #plane2
  # v3y=`calc "($y2)-($y3)" | sed 's/^\t//g'` #plane2
  # v3z=`calc "($z2)-($z3)" | sed 's/^\t//g'` #plane2
  # v4x=`calc "($x3)-($x4)" | sed 's/^\t//g'` #plane2
  # v4y=`calc "($y3)-($y4)" | sed 's/^\t//g'` #plane2
  # v4z=`calc "($z3)-($z4)" | sed 's/^\t//g'` #plane2

  v1x=x2-x1 ; v1y=y2-y1 ; v1z=z2-z1     #plane1
  v2x=x3-x2 ; v2y=y3-y2 ; v2z=z3-z2     #plane1
  v3x=x2-x3 ; v3y=y2-y3 ; v3z=z2-z3     #plane2
  v1x=x2-x1 ; v1y=y2-y1 ; v1z=z2-z1     #plane1
  v2x=x3-x2 ; v2y=y3-y2 ; v2z=z3-z2     #plane1
  v3x=x2-x3 ; v3y=y2-y3 ; v3z=z2-z3     #plane2
  v4x=x3-x4 ; v4y=y3-y4 ; v4z=z3-z4     #plane2 

  # plane1_x=`calc "($v1y)*($v2z)-($v1z)*($v2y)" | sed 's/^\t//g'` # normal vector 1
  # plane1_y=`calc "($v2x)*($v1z)-($v2z)*($v1x)" | sed 's/^\t//g'` # normal vector 1
  # plane1_z=`calc "($v1x)*($v2y)-($v1y)*($v2x)" | sed 's/^\t//g'` # normal vector 1
  # plane2_x=`calc "($v3y)*($v4z)-($v3z)*($v4y)" | sed 's/^\t//g'` # normal vector 2
  # plane2_y=`calc "($v4x)*($v3z)-($v4z)*($v3x)" | sed 's/^\t//g'` # normal vector 2
  # plane2_z=`calc "($v3x)*($v4y)-($v3y)*($v4x)" | sed 's/^\t//g'` # normal vector 2

  plane1_x=(v1y*v2z)-(v1z*v2y)  # normal vector 1
  plane1_y=(v2x*v1z)-(v2z*v1x)  # normal vector 1
  plane1_z=(v1x*v2y)-(v1y*v2x)  # normal vector 1
  plane2_x=(v3y*v4z)-(v3z*v4y)  # normal vector 2
  plane2_y=(v4x*v3z)-(v4z*v3x)  # normal vector 2
  plane2_z=(v3x*v4y)-(v3y*v4x)  # normal vector 2

  # v1mag=`calc "sqrt(($plane1_x)**2+($plane1_y)**2+($plane1_z)**2)" | sed 's/^\t//g'`  # magnitude normal vector 1
  # v2mag=`calc "sqrt(($plane2_x)**2+($plane2_y)**2+($plane2_z)**2)" | sed 's/^\t//g'`  # magnitude normal vector 2

  v1mag=sqrt((plane1_x)**2+(plane1_y)**2+(plane1_z)**2) # magnitude normal vector 1
  v2mag=sqrt((plane2_x)**2+(plane2_y)**2+(plane2_z)**2) # magnitude normal vector 2

  # vn1x=`calc "($plane1_x)/($v1mag)" | sed 's/^\t//g'`  # normalization normal vector 1
  # vn1y=`calc "($plane1_y)/($v1mag)" | sed 's/^\t//g'`  # normalization normal vector 1
  # vn1z=`calc "($plane1_z)/($v1mag)" | sed 's/^\t//g'`  # normalization normal vector 1
  # vn2x=`calc "($plane2_x)/($v2mag)" | sed 's/^\t//g'`  # normalization normal vector 2
  # vn2y=`calc "($plane2_y)/($v2mag)" | sed 's/^\t//g'`  # normalization normal vector 2
  # vn2z=`calc "($plane2_z)/($v2mag)" | sed 's/^\t//g'`  # normalization normal vector 2

  vn1x=(plane1_x)/(v1mag) ; vn1y=(plane1_y)/(v1mag) ; vn1z=(plane1_z)/(v1mag) # normalization normal vector 1
  vn2x=(plane2_x)/(v2mag) ; vn2y=(plane2_y)/(v2mag) ; vn2z=(plane2_z)/(v2mag) # normalization normal vector 2

  # calc "acos(($vn1x)*($vn2x)+($vn1y)*($vn2y)+($vn1z)*($vn2z))*180/3.141592653589793" | sed 's/^\t//g' | sed 's/^~//g'

  print acos((vn1x*vn2x)+(vn1y*vn2y)+(vn1z*vn2z))*180/3.141592653589793
}

EDIT: If your internet search for torsion.awk has brought you here, just skip up above to the accepted answer, as it uses the O.P.s refined algorithm to calculate torsion but still demonstrates converting shell code to awk.

Previous readers, also note improvements to using this code in the 2nd edit below.


I Just noticed the "properly" qualifcation at the end ;-/

Here's your code converted to one awk process.

I have no experience with this level of math, so can't say that it is really calculating the result you need.

Also, there are often questions about precision in awk programs which really relates to the underlying c language libraries that are compiled in.

Anyway, with all of the caveats, here's an basic conversion of your code.

cat torsion_docd.awk

#!/bin/awk -f

function acos(x)        { return atan2((1.-x^2)^0.5,x) }

# x1=`awk '{print $2}' LINEA` # x1
# y1=`awk '{print $3}' LINEA` # y1
# z1=`awk '{print $4}' LINEA` # z1
# x2=`awk '{print $2}' LINEB` # x2
# y2=`awk '{print $3}' LINEB` # y2
# z2=`awk '{print $4}' LINEB` # z2
# x3=`awk '{print $2}' LINEC` # x3
# y3=`awk '{print $3}' LINEC` # y3
# z3=`awk '{print $4}' LINEC` # z3
# x4=`awk '{print $2}' LINED` # x4
# y4=`awk '{print $3}' LINED` # y4
# z4=`awk '{print $4}' LINED` # z4
NR==1 {x1=$2; y=$3; z1=$4}
NR==2 {x2=$2; y=$3; z2=$4}
NR==3 {x3=$2; y=$3; z3=$4}
NR==4 {
        x4=$2; y=$3; z4=$4

        # all of this code below is only executed when you read in the 4th line
        # becuase then you have all the data
        # v1x=`calc "($x1)-($x2)" | sed 's/^\t//g'`
        # v1y=`calc "($y1)-($y2)" | sed 's/^\t//g'`
        # v1z=`calc "($z1)-($z2)" | sed 's/^\t//g'`
        # v2x=`calc "($x4)-($x3)" | sed 's/^\t//g'`
        # v2y=`calc "($y4)-($y3)" | sed 's/^\t//g'`
        # v2z=`calc "($z4)-($z3)" | sed 's/^\t//g'`

        v1x=x1-x2 ; v1y=y1-y2 ; v1z=z1-z2
        v2x=x4-x3 ; v2y=y4-y3 ; v2z=z4-z3

        # v1mag=`calc "sqrt(($v1x)**2+($v1y)**2+($v1z)**2)" | sed 's/^\t//g'`
        # v2mag=`calc "sqrt(($v2x)**2+($v2y)**2+($v2z)**2)" | sed 's/^\t//g'`

        v1mag=sqrt((v1x)**2+(v1y)**2+(v1z)**2)
        v2mag=sqrt((v2x)**2+(v2y)**2+(v2z)**2)   

        # calc "acos((($v1x)/($v1mag))*(($v2x)/($v2mag))+(($v1y)/($v1mag))*(($v2y)/($v2mag))+(($v1z)/($v1mag))*(($v2z)/($v2mag)))*180/3.141
592653589793" | sed 's/^\t//g' | sed 's/^~//g'
        # calc "acos((($x1)*($x4)+($y1)*($y4)+($z1)*($z4))/(sqrt(($x1)**2+($y1)**2+($z1)**2)*sqrt(($x4)**2+($y4)**2+($z4)**2)))*180/3.14159
2653589793" | sed 's/^\t//g' | sed 's/^~//g'

        print acos(((v1x)/(v1mag))*((v2x)/(v2mag))+((v1y)/(v1mag))*((v2y)/(v2mag))+((v1z)/(v1mag))*((v2z)/(v2mag)))*180/3.141592653589793
        print acos(((x1)*(x4)+(y1)*(y4)+(z1)*(z4))/(sqrt((x1)**2+(y1)**2+(z1)**2)*sqrt((x4)**2+(y4)**2+(z4)**2)))*180/3.141592653589793
}

And without the conversion documentation, it looks like

cat torsion.awk

#!/bin/awk -f

function acos(x)        { return atan2((1.-x^2)^0.5,x) }

NR==1 {x1=$2; y=$3; z1=$4}
NR==2 {x2=$2; y=$3; z2=$4}
NR==3 {x3=$2; y=$3; z3=$4}
NR==4 {
        x4=$2; y=$3; z4=$4

        # all of this code below is only executed when you read in the 4th line
        # because then you have all the data

        v1x=x1-x2 ; v1y=y1-y2 ; v1z=z1-z2
        v2x=x4-x3 ; v2y=y4-y3 ; v2z=z4-z3

        v1mag=sqrt((v1x)**2+(v1y)**2+(v1z)**2)
        v2mag=sqrt((v2x)**2+(v2y)**2+(v2z)**2)   

        print acos(((v1x)/(v1mag))*((v2x)/(v2mag))+((v1y)/(v1mag))*((v2y)/(v2mag))+((v1z)/(v1mag))*((v2z)/(v2mag)))*180/3.141592653589793
        print acos(((x1)*(x4)+(y1)*(y4)+(z1)*(z4))/(sqrt((x1)**2+(y1)**2+(z1)**2)*sqrt((x4)**2+(y4)**2+(z4)**2)))*180/3.141592653589793
}

Note that I added print statements in front of your last 2 lines acos.

On my machine, I run it as

awk -f torsion.awk data.txt

EDIT : I've fixed #!/bin/awk at the top of script. So you then need to mark the script as executable with

 chmod +x ./torsion.awk

And then you can run it just as

`./torsion.awk data.txt

Your system may require a different path to awk as in the she-bang line at the top (#!/bin/awk). Type which awk, and then use that value after the #!. Also, legacy Unix implementations often have other versions of awk installed, so if that is your operating environment, do some research to find out which is the best awk on your system (often times it is gawk).

# -------------- end edit --------------------

output

87.6318
131.872

But given you agreed that -58.7 is your desired output, I'll have leave it to you for how to use the 2 acos calculations.

In any case, hopefully you can see how much more straight forward is is to use awk for such calculations.

Of course, hoping that true mathheads to wade in (after a good laugh) and help correct this (or offer their own ideas).

IHTH

After a long night, I found the solution:

awk -v var=$((x+2)) 'NR==var' $FILE > LINEaa
awk -v var=$((y+2)) 'NR==var' $FILE > LINEbb
awk -v var=$((z+2)) 'NR==var' $FILE > LINEcc
awk -v var=$((w+2)) 'NR==var' $FILE > LINEd
x1=`awk '{print $2}' LINEaa` # x1
y1=`awk '{print $3}' LINEaa` # y1
z1=`awk '{print $4}' LINEaa` # z1
x2=`awk '{print $2}' LINEbb` # x2
y2=`awk '{print $3}' LINEbb` # y2
z2=`awk '{print $4}' LINEbb` # z2
x3=`awk '{print $2}' LINEcc` # x3
y3=`awk '{print $3}' LINEcc` # y3
z3=`awk '{print $4}' LINEcc` # z3
x4=`awk '{print $2}' LINEd` # x4
y4=`awk '{print $3}' LINEd` # y4
z4=`awk '{print $4}' LINEd` # z4
v1x=`calc "($x2)-($x1)" | sed 's/^\t//g'` #plane1
v1y=`calc "($y2)-($y1)" | sed 's/^\t//g'` #plane1
v1z=`calc "($z2)-($z1)" | sed 's/^\t//g'` #plane1
v2x=`calc "($x3)-($x2)" | sed 's/^\t//g'` #plane1
v2y=`calc "($y3)-($y2)" | sed 's/^\t//g'` #plane1
v2z=`calc "($z3)-($z2)" | sed 's/^\t//g'` #plane1
v3x=`calc "($x2)-($x3)" | sed 's/^\t//g'` #plane2
v3y=`calc "($y2)-($y3)" | sed 's/^\t//g'` #plane2
v3z=`calc "($z2)-($z3)" | sed 's/^\t//g'` #plane2
v4x=`calc "($x3)-($x4)" | sed 's/^\t//g'` #plane2
v4y=`calc "($y3)-($y4)" | sed 's/^\t//g'` #plane2
v4z=`calc "($z3)-($z4)" | sed 's/^\t//g'` #plane2
plane1_x=`calc "($v1y)*($v2z)-($v1z)*($v2y)" | sed 's/^\t//g'` # normal vector 1
plane1_y=`calc "($v2x)*($v1z)-($v2z)*($v1x)" | sed 's/^\t//g'` # normal vector 1
plane1_z=`calc "($v1x)*($v2y)-($v1y)*($v2x)" | sed 's/^\t//g'` # normal vector 1
plane2_x=`calc "($v3y)*($v4z)-($v3z)*($v4y)" | sed 's/^\t//g'` # normal vector 2
plane2_y=`calc "($v4x)*($v3z)-($v4z)*($v3x)" | sed 's/^\t//g'` # normal vector 2
plane2_z=`calc "($v3x)*($v4y)-($v3y)*($v4x)" | sed 's/^\t//g'` # normal vector 2
v1mag=`calc "sqrt(($plane1_x)**2+($plane1_y)**2+($plane1_z)**2)" | sed 's/^\t//g'`  # magnitude normal vector 1
v2mag=`calc "sqrt(($plane2_x)**2+($plane2_y)**2+($plane2_z)**2)" | sed 's/^\t//g'`  # magnitude normal vector 2
vn1x=`calc "($plane1_x)/($v1mag)" | sed 's/^\t//g'`  # normalization normal vector 1
vn1y=`calc "($plane1_y)/($v1mag)" | sed 's/^\t//g'`  # normalization normal vector 1
vn1z=`calc "($plane1_z)/($v1mag)" | sed 's/^\t//g'`  # normalization normal vector 1
vn2x=`calc "($plane2_x)/($v2mag)" | sed 's/^\t//g'`  # normalization normal vector 2
vn2y=`calc "($plane2_y)/($v2mag)" | sed 's/^\t//g'`  # normalization normal vector 2
vn2z=`calc "($plane2_z)/($v2mag)" | sed 's/^\t//g'`  # normalization normal vector 2
calc "acos(($vn1x)*($vn2x)+($vn1y)*($vn2y)+($vn1z)*($vn2z))*180/3.141592653589793" | sed 's/^\t//g' | sed 's/^~//g'
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!