#!/usr/bin/perl -w
# Rowin Andruscavage
# MAE 470 Design Project
# glue gno3dtet to slffea to get FEAtris

# Main processing loop
foreach $line (<>) {	# read data from gno3dtet from stdin
    if ($line =~ s/Bounds\: //) {	# get width/height/depth 
	@bound = split(/ /, $line);	# of playing field
    }
    if ($line =~ s/Coords\: //) {	# get block coordinates
	chop($line);			# excise that trailing ';'
	@elements = split (/;/, $line);
	$n=0;				# initialize element number
	$nn=0;				# initialize node number 
	foreach $element (@elements) {
	    # extract element positions
	    ($ex[$n], $ey[$n], $ez[$n]) = split(/ /,$element);
	    # build a list of nodes from the 8 corners of the cube
	    $i = 1;
	    foreach $k (1,0) {
		foreach $j (1,1,0,0) {	# vertices ordered to form convex hull
		    # x, y, z positions of each block :
		    my $pos = ($ex[$n]-$i-$bound[0]/2)." ".(-$ey[$n]-$j+$bound[1]/2)." ".($ez[$n]-$k-$bound[2]/2);
		    # if thie node doesn't exist yet,
		    if(!exists($node{$pos})){ 
			$node{$pos} = $nn;	# create a new node number
			$conn[$n] .= $nn . " ";	# element->node connectivity matrix

			# Apply loads and boundary conditions :
			# assign fixed boundary conditions if z=0
			if ($ez[$n]-$k == 0) {
			    $bcx .= "    $nn    0.0\n";
			    $bcy .= "    $nn    0.0\n";
			    $bcz .= "    $nn    0.0\n";
			} 
			else { # assign gravitational & "wind" loads otherwise
			    $ld .= "    $nn    0.0  300.0  -500.0\n";
			}

			$nn++;	# increment the node number
		    } else {
			# if node already exists, just add it to the 
			# connectivity matrix
			$conn[$n] .= $node{$pos} . " "; 
		    }
		    # flip $i if $i = $j 
		    if ($i == $j) { $i = ($i == 0) ? 1 : 0; }
		}}
	    $n++;	# increment element number
	}
    }
}  # That's it!  Everything else is all formatting and file handling

# Output this turn of events in an slffea format file
open(FEAFILE, ">featris") || die "featris file: $!"; 
print FEAFILE "   numel numnp nmat  nmode  (This is for a FEAtris brick)\n	" . ($#elements+1) . "   $nn  1  0\n";
print FEAFILE "matl no., E modulus, Poisson Ratio,density\n0    3000000.0   0.35    2e3\n";
print FEAFILE "el no.,connectivity, matl no\n";
for ($i = 0; $i<$n; $i++) {
    print FEAFILE $i . "     " . $conn[$i] . "    0\n";
}

print FEAFILE "node no. coordinates\n";
foreach $nnum (keys(%node)) {
    print FEAFILE "$node{$nnum}    $nnum\n";
}

print FEAFILE "prescribed displacement x: node  disp value\n$bcx";
print FEAFILE "    -10\nprescribed displacement y: node  disp value\n$bcy";
print FEAFILE "    -10\nprescribed displacement z: node  disp value\n$bcz";
print FEAFILE "    -10\nnode with point load and load vector in x,y,z\n$ld";
print FEAFILE "    -10\nnode no. with stress and stress vector in xx,yy,zz,xy,zx,yz\n";
print FEAFILE "    -10\n";
close(FEAFILE);

# run the FEA
`echo "featris" | ./br > brlog.txt` || print STDERR "couldn't exec br: $!";

# check satisfaction of "winning" conditions
open (FEARESULTS, "featris.obr") || die "can't open featris.obr: $!";

# Keep track of what kind of data we're looking at
foreach $line (<FEARESULTS>) {
    if ($line =~ /numel numnp nmat nmode/) 
    {$mode = "summary"; next;}
    elsif ($line =~ /E modulus, Poisson Ratio, density/)
    {$mode = "matlprop"; next;}
    elsif ($line =~ /connectivity/)
    {$mode = "connectivity"; next;}
    elsif ($line =~ /coordinates/)
    {$mode = "solution"; next;}
    elsif ($line =~ /prescribed displacement x/)
    {$mode = ""; last;}
# Things that can be added in the future :
#    {$mode = "xdisp"; next;}
#    elsif ($line =~ /prescribed displacement y: node  disp value/)
#    {$mode = "ydisp"; next;}
#    elsif ($line =~ /prescribed displacement z: node  disp value/)
#    {$mode = "zdisp"; next;}
#    elsif ($line =~ //)
#    {$mode = ""; next;}
    
    if ($mode =~ /solution/) {
	# load solution coordinates
	($blah, $nodenum, $xpos, $ypos, $zpos) = split(/\s+/,$line);
	# check to see if "winning condition" has been satisfied.  In
	# this case, we're checking if any node is taller than 11
	# units ... tricky, because the 3D tetris program only allows
	# us to build them 10 high.  We have to design the structure
	# to deform in such a way as to elevate a node above 11 units.
	if ($zpos > 11-$bound[2]/2) {
	    open(SCOREFILE, ">winmesg.txt");
	    print SCOREFILE sprintf("Objective complete!  Score : %d blocks used", $n);
	    close(SCOREFILE);
	    # pop up an annoying message to tell you you've won
	    `xmessage -file winmesg.txt`; 
	    last;
	}
    }
}

close (FEARESULTS);

# Forcibly restart the post processor to show the results of your new addition
`killall brpost` || print STDERR "couldn't kill old brpost: $!";
exec('echo "featris" | ./brpost > brpostlog.txt &') || print STDERR "couldn't exec brpost: $!";

# Misc. debugging output
#print "-Bounds: @bound\n";
#print "-Coords: @elements\n";
#print "-Nodes: \n";	# node positions
#foreach $key (keys %node) {
#    print $key . " = " . $node{$key} . "\n";
#}
#foreach (@conn) {
#    print $_ . "\n";	# connectivity matrix
#}
#print "N: $nodenum , $xpos, $ypos, $zpos \n"; # solution position

