#!/usr/bin/perl -w #-d
# $Header$
# usage: ugexo2lgm <exo2filename> <lgmfilename>
# 		<exo2filename> - exodus II file with surface triangulation and node 
#					 assoziativity info
#       <lgmfilename> - lgm file to create
#
# author: Stefan Lang, INF 368, IWR, University of Heidelberg
#         Stefan.Lang@iwr.uni-heidelberg.de
# history: start 030907

# basic data types
#$num = '\d';
$int = '\d+';
#$sint = '[+-]?\d+';
$real = '[+-]?\d+(?:\.\d+)?';   # (?:\.\d+)? means: optional .nnnn part
$exp = '[+-]?\d+(?:\.\d+(?:e[+-]?\d+)?)?';
$string = '[a-z"_]\w*';

%cdf = ();

if ($#ARGV != 2)
{
	print "usage: ugexo2lgm <exo2filename> <lgmfilename> <mapfilename>\n";
 	exit;
}

$exo2 = "$ARGV[0]";
$lgm = "$ARGV[1]";
$map = "$ARGV[2]";


print "processing $exo2\n";

sub	scan_nsets
{
	my $nsets = $_[0];

#	print "nsets: $nsets\n";
	$nns = 0;
	$ready = 0;
	LOOP1: while (1)
	{
		if ($nns == $nsets) { last LOOP1; }
		LOOP: while(<EXO2>)
		{
			if ( /^\s($string)/ )
			{
#				print "scan_node_sets: string $1\n";
				$record = $1;
				$i = 0;
				$found = 0;
			}
			for $_ (split)
			{
#				if ( /($exp)/  || /($exp),/ ) { printf "$record %s\n", $1; }
				if ( 
					/($exp)/ || /($exp),/   ||
					/($real)/ || /($real),/ ||
					/($int)/  || /($int),/ || 
 					/($string)/ || /($string),/
				   )
				{
#   					print "scan_node_sets: record $record $i $1\n";
					$cdf{$record}{$i} = $1; 

					$i++;
				}
 				elsif ( /=/ ) { $found++; }
				elsif ( /;/ ) { $nns++; last LOOP; }
				elsif ( /}/ ) { $ready = 1; last LOOP; }
				else { printf "error %s\n",$_;  print "ERROR while reading node_sets\n"; exit;}
			}
		}
		if ($ready == 1) { last LOOP1; }
#		print "scan_node_sets: $nns\n";
	}
}

sub scan_dimension
{
	print "found dimensions block\n";

	$token = 0; 
	LOOP: while(<EXO2>)
	{
		if ( /\s*num_dim\s*=\s*($int)\s*;/ ) { $cdf{num_dim} = $1; $token++;}
		if ( /\s*num_nodes\s*=\s*($int)\s*;/ ) { $cdf{num_nodes} = $1; $token++;}
		if ( /\s*num_node_sets\s*=\s*($int)\s*;/ )
		{
			$cdf{num_node_sets} = $1; 
 			scan_nsets($cdf{num_node_sets});
			$token++;
#			print "scan_dimension: $token\n";
		}
		if ( /\s*num_el_blk\s*=\s*($int)\s*;/ )
		{
			$cdf{num_el_blk} = $1; 
 			scan_nsets(2*$cdf{num_el_blk});
			$token++;
#			print "scan_dimension: $token\n";
		}
		if ($token == 4) { last LOOP; }
	}

	return(0);
}


sub scan_variables
{
	print "found variables block\n";

	LOOP: while(<EXO2>)
	{
		if ( /\s*num_dim\s*=\s*($int)\s*;/ ) { $cdf{num_dim} = $1; }
		else {last LOOP; }
	}

	return(0);
}

sub scan_globalattributes
{
	print "found attributes block\n";

	LOOP: while(<EXO2>)
	{
		if ( /\s*num_dim\s*=\s*($int)\s*;/ ) { $cdf{num_dim} = $1; }
		else {last LOOP; }
	}

	return(0);
}

sub scan_coord
{
	$i = 0;
	$dim = 0;
	LOOP: while(<EXO2>)
	{
#		@coordline = split;
#		print "$_\n";
		for $_ (split)
		{
#			print "$cdf{num_nodes} $i\n";
			if ( /($real),/ )
			{
				$cdf{coord}{$i}{$dim} = $1; $i++;
				if ($i == $cdf{num_nodes})
				{
					$i = 0; $dim++;
				}
			}
			elsif ( /($real)/ )
			{
				$cdf{coord}{$i}{$dim} = $1; $i++; $dim++;
			}
			elsif ( /;/ ) 
			{
				if ($i != $cdf{num_nodes})
				{ print "ERROR: scaned coord=$i but num_nodes=$cdf{num_nodes}\n"; exit;}
				if ($dim != $cdf{num_dim})
				{ print "ERROR: scaned dim=$i but num_dim=$cdf{num_dim}\n"; exit;}
				last LOOP;
			} 
			else { print "ERROR while reading coord\n";}
		}
	}
}

sub scan_node_sets
{
	# skip ns_status record
	LOOP2: while(<EXO2>)
	{
		if ( /;/ ) { last LOOP2; }
	}

	# read ns_prop1 record +  n node_ns/dist_face_ns records
 	scan_nsets(2*$cdf{num_node_sets}+1);
}

sub scan_data
{
	print "found data block\n";

	$found = 0;
	LOOP: while(<EXO2>)
	{
		if ( /\s*coord\s*=\s*/ ) { scan_coord(); $found++}
		elsif ( /\s*ns_status\s*=\s*/ ) { scan_node_sets(); $found++}
		elsif ($found == 2) {last LOOP; }
	}

	return(0);
}

sub scan_modeldata ()
{
	$nunits = 0;
	$cdf{unitsrev}{0} = 0;

	LOOP: while(<EXO2>)
	{
		if ( /Volume\sEntity\s*\(Id\s=\s($int)\)/ )
		{
#			printf "unit %d material%d\n",$1,$1;
			$cdf{units}{$nunits} = $1;
			$cdf{unitsrev}{$1} = $nunits+1;
			$nunits++;
		}
		if ( /Surface\sEntity\s*\(Id\s=\s($int)\)/ )
		{
			$surface = $1;
			$nl = 0;
			LOOP1: while(<EXO2>)
			{
				$surfacename = sprintf "surface%d",$surface; 
				if ( /In\sVolume\s*($int)\./ )
				{
# 					printf "surface %d left=0 right=%d\n",$surface,$1;
					$cdf{$surfacename}{left} = 0;
					$cdf{$surfacename}{right} = $1;
					last LOOP1;
				}
				elsif ( /In\sVolume\s*($int),\s*Volume\s*($int)\./ )
				{
# 					printf "surface %d left=%d right=%d\n",$surface,$1,$2;
					if ($1 < $2)
					{
						$cdf{$surfacename}{left} = $2;
						$cdf{$surfacename}{right} = $1;
					}
					else
					{
						$cdf{$surfacename}{left} = $1;
						$cdf{$surfacename}{right} = $2;
					}
					last LOOP1;
				}
				elsif ( /\s*Curve\s*($int)\s*($int)/ )
				{
					$cdf{$surfacename}{lines}{$nl} = $2;
					if ( $1 != $2 ) { printf "ERROR curve name $1 differs from its id $2\n"; }
					$nl++;
				}
				else { printf "ERROR: left/right or curve information missing for surface %d\n",$surface; exit;}
			}
			$cdf{$surfacename}{lines}{nlines} = $nl;
		}
	}

	$cdf{nunits} = $nunits;

}

# read exodus II format
sub read_exo2()
{
	open(EXO2, "<$exo2") || die "can't open $exo2\n";

	BEGIN: while(<EXO2>)
	{
		last BEGIN if ( /^netcdf\s\w+\s\{/ ); 
		print "$exo2 has no valid netcdf file format!\n";
		exit;
	}

	$end = 0;
	END: while(<EXO2>)
	{
		if ( /dimensions:/ ) { scan_dimension(); }
		if ( /variables:/ ) { scan_variables(); }
		if ( /global\sattributes:/ ) { scan_globalattributes(); }
#		if ( /data:/) { scan_data(); }
 		if ( /data:/) { print "found data block\n"; scan_nsets(-1); }
		if ( /\}/ ) { $end = 1; last END; }
	}

	if ($end == 0) { print "file $exo2 not complete!!\n"} 

	# scan added model data for units and surface left/right
	scan_modeldata();

	close(EXO2);

	return(0);
}

#######################################################################################

sub write_domain
{
	printf LGM "# Domain-Info\n";
	print LGM "name = default_name\n";
	print LGM "problemname = default_problem\n";
	print LGM "convex = 1\n";
	print LGM "\n";
}

sub write_unit
{
	print LGM "# Unit-Info\n";
	
	LOOP: foreach $nus (0 .. $cdf{nunits}-1)
	{
		printf LGM "unit %d MATERIAL1\n",$nus+1;
	}

	print LGM "\n";
}

sub write_line
{
	print LGM "# Line-Info\n";
	printf MAP " Line-Map\n";
	$nl = 0;
	foreach $nns (1 .. $cdf{num_node_sets})
	{
#		print "$cdf{ns_prop1}{$nns}\n";
		if ( $cdf{ns_prop1}{$nns} =~/\A4($int)/ )
		{
			$linestring = $1;
#			print "match $cdf{ns_prop1}{$nns}\n"; 
# 			if ($nl == 74) { print "ERROR line $nl has id $1\n"; }
			printf MAP " %4d %4d\n",$linestring,$nl;
#			printf LGM "#       cubit lineid %d\n",$linestring;
			printf LGM "line %d:",$nl;
			$ns = sprintf "node_ns%d",$nns; 
			$numns = sprintf "num_nod_ns%d",$nns; 
# 			print "$ns $numns $cdf{$numns}{1}\n";

 			print LGM " points:";
			$numnp = sprintf "node_ns%d",$nns; 
			foreach $np (1 .. $cdf{$numns}{1})
			{
				printf LGM " %d",$cdf{$numnp}{$np}-1;
			}
			print LGM ";\n";
			
			$line = sprintf "%d",$linestring; 
			$cdf{linemap}{$line} = $nl;
#			printf "new line %s = %d %d\n", $line, $cdf{linemap}{$line}, $nl;
			$nl++;
		}
	}
	print LGM "\n";
}

sub write_surflines
{
	my $surfacename = $_[0];

	foreach $nns (0 .. $cdf{$surfacename}{lines}{nlines}-1)
	{
#		printf "line id %d\n", $cdf{$surfacename}{lines}{$nns};
#		$test = $cdf{linemap}{$cdf{$surfacename}{lines}{$nns}}; 
#		printf LGM " %d", $test;
		printf LGM " %d", $cdf{linemap}{$cdf{$surfacename}{lines}{$nns}}; 
	}
}

sub search_lines
{
	my $spoints = $_[0];
	my $nsp = $_[1];

#	printf "%s=%s",$spoints,$cdf{$spoints}{0};

	$nl = 0;
	LOOP: foreach $nns (1 .. $cdf{num_node_sets})
	{
		if ( $cdf{ns_prop1}{$nns} =~/\A4($int)/ )
		{
			$found = 1;
			$ns = sprintf "node_ns%d",$nns; 
			$numns = sprintf "num_nod_ns%d",$nns; 

			$numnp = sprintf "node_ns%d",$nns; 
			LOOP1: foreach $np (1 .. $cdf{$numns}{1})
			{
				foreach $ns (1 .. $cdf{$nsp}{1})
				{
					if ( $cdf{$spoints}{$ns} == $cdf{$numnp}{$np} ) { next LOOP1;}
				}
				$found = 0;
				last LOOP1;
			}
			if ($found == 1)
			{
# 				if ($nl == 74) { print "ERROR line $nl added to surface $spoints\n"; }
				printf LGM " %d",$nl; 
			}
			$nl++;
		}
	}
}

sub write_surf
{
	print LGM "# Surface-Info\n";
	printf MAP " Surface-Map\n";
	$nsurf = 0;
	foreach $nns (1 .. $cdf{num_node_sets})
	{
#		print "$cdf{ns_prop1}{$nns}\n";
		if ( $cdf{ns_prop1}{$nns} =~/\A3($int)/ )
		{
			$surf = $1;
#			printf "writing surface $1 ";
#			print "match $cdf{ns_prop1}{$nns}\n"; 
			printf MAP " %4d %4d\n",$surf,$nsurf;
#			printf LGM "#         cubit surfaceid %d\n",$surf;
			printf LGM "surface %d:",$nsurf;
			$nsurf++;

			$surfacename = sprintf "surface%d",$surf;
  			printf LGM " left=%d; right=%d;",
  				$cdf{unitsrev}{$cdf{$surfacename}{left}},
  				$cdf{unitsrev}{$cdf{$surfacename}{right}};
			
			$ns = sprintf "node_ns%d",$nns; 
			$numns = sprintf "num_nod_ns%d",$nns; 
# 			print "$ns $numns $cdf{$numns}{1}\n";

 			print LGM " points:";
			$numnp = sprintf "node_ns%d",$nns; 
			foreach $np (1 .. $cdf{$numns}{1})
			{
				printf LGM " %d",$cdf{$numnp}{$np}-1;
			}
			print LGM ";";

 			print LGM " lines:";
			write_surflines($surfacename);
#			search_lines($numnp,$numns);
			print LGM ";";

 			print LGM " triangles:";
			# index of surface $1 in eb_prop1
			$ncon = 0;
			LOOP: foreach $nconnect (1 .. $cdf{num_el_blk})
			{
				if ( $cdf{eb_prop1}{$nconnect} =~/\A3($int)/ )
				{
					if ($surf == $1) { $ncon = $nconnect; last LOOP;}
				}
			}
			# number of triangles in block $1
			$numnt = sprintf "num_el_in_blk%d",$ncon; 
			# hash of triangles
			$connect = sprintf "connect%d",$ncon; 
#			print "$numnt;\n";
			# print triangles
#			printf "ERROR %s %d\n", $numnt, $cdf{$numnt}{1};
			foreach $nt (1 .. $cdf{$numnt}{1})
			{
				printf LGM " %d", $cdf{$connect}{3*$nt-2}-1;
				printf LGM " %d", $cdf{$connect}{3*$nt-1}-1;
				printf LGM " %d;", $cdf{$connect}{3*$nt-0}-1;
			}
			print LGM "\n";
		}
	}
	print LGM "\n";
}

sub write_coord
{
	print LGM "# Point-Info\n";
#	printf "%d\n",$cdf{num_nodes};
#	printf "%s %s\n", $cdf{coord}{0},$cdf{coord}{1};
#	printf "%s\n", $cdf{coord};
	foreach $nc (1 .. $cdf{num_nodes})
	{
#    		printf "%lf, %lf, %lf\n",$cdf{coord}{$nc-1},$cdf{coord}{2*$nc-1},$cdf{coord}{3*$nc-1};
    		printf LGM "%s %s %s;\n",
				$cdf{coord}{$nc},$cdf{coord}{$nc+$cdf{num_nodes}},$cdf{coord}{$nc+2*$cdf{num_nodes}}; 
	}	
	print LGM "\n";
}


# write lgm
sub write_lgm()
{
	print "writing lgm geometry file $lgm\n";
	open(LGM, ">$lgm") || die "can't open $lgm\n";

	open(MAP, ">$map") || die "can't open $map\n";
	printf MAP "Map file created by ugexo2lgm\n";
	printf MAP "Map from cubit lines/surfaces to lgm lines/surfaces\n";
	printf MAP "Map valid for file %s\n",$exo2;
	printf MAP "Map created at %s\n",$s=localtime;

	write_domain();
	write_unit();
	write_line();
 	write_surf();
 	write_coord();

	printf LGM "\n# Domain-Info created at %s\n",$s=localtime;

	close(MAP);
	close(LGM);
}

sub main()
{
	read_exo2();
  	write_lgm();
}

main();

exit;

