#!/usr/bin/env perl
#!/usr/local/bin/perl -w
#
# Albert Danial Oct. 12 2003
#
use lib "$ENV{TOPS_HOME}/apps/fea/util"; # for module TopsFEA
use TopsFEA qw ( %nNodes_in_element );
use Getopt::Std;
use vars qw ( $opt_n $opt_e $opt_r );
use Time::HiRes qw( time );
#use Data::Dumper;
use File::Basename;
use strict;
getopts('enr');

my $script = basename $0;  # Usage instructions {{{1
getopts('ne');
die "$script [options] <.db file>
                  Time how long it takes to find node coordinates and material 
                  values for every element in the database.

             Options:
             -e     Loop over every element and extract its nodes' coodinates
                    and material values.
             -n     Loop over every node and determine its adjacent nodes.
                    (-n is inefficient, use -r for a better method)
             -r     Compute the renumbered table structure.

" unless @ARGV and ($opt_n or $opt_e or $opt_r );

my $db_file = shift @ARGV;
die "Cannot read $db_file" unless -r $db_file;
# 1}}}

my $dbh = DBI->connect("dbi:SQLite:dbname=$db_file","","");
my $st;
$| = 1; # flush STDOUT

if      ($opt_e) { # element access {{{1
    my $start_t  = time;
    my $n_elem   = 0;
    my $start_ti = time;  # interval timings
    my $end_ti   = 0;     # interval timings
    my $SET_SIZE = 500;
    my $rh_table = $dbh->selectall_hashref("select name from schema", "name");
    foreach my $T (sort keys %{$rh_table}) { # loop over all tables in the database
        next unless $nNodes_in_element{$T};  # skip unless this is an element table
        my $rh_eid = $dbh->selectall_hashref("select id from $T", "id");
        foreach my $eid (sort keys %{$rh_eid}) {
            if (1) {
            my $ra_nodes  = $dbh->selectall_arrayref(
                    "select R.new_id, N.x1, N.x2, N.x3 "
                    .   "from element_node E, node N, renumbered_nid R "
                    .   "where E.eid='$eid' and E.nid=N.id and R.orig_id=N.id "
                    .   "order by E.seq_no;"
                    );
            }

            if (1) {
            my $ra_props  = $dbh->selectall_arrayref(
                    "select E,nu,rho,thick from tri3,shell_prop,material "
                    .   "where tri3.id='$eid' and tri3.shell_prop=shell_prop.id "
                    .       "and material.id=shell_prop.material_id;"
                    );
            }
            ++$n_elem;
            if (!($n_elem % $SET_SIZE)) {
                $end_ti   = time;
                printf "# element joins: %9d   (%.2f elem/sec)\r", 
                        $n_elem, $SET_SIZE/($end_ti - $start_ti);
                $start_ti = $end_ti;
            }
        }
    }
    $st = $dbh->disconnect;
    my $end_t = time;
    printf "# element joins: %9d\n", $n_elem;

    printf "Data extraction for %d elements in %.2f sec  (%.2f elem/sec)\n",
            $n_elem, ($end_t - $start_t), $n_elem/($end_t - $start_t);

# 1}}}
} elsif ($opt_n) { # node-node connectivity  {{{1
    # performance relies on element_node(nid) index
    my $start_t  = time;
    my $start_ti = time;  # interval timings
    my $end_ti   = 0;     # interval timings
    my $n_node   = 0;
    my $n_NNZ    = 0;     # the number of node-node pairs * 6^2 = # non-zeros g set
    my $SET_SIZE = 1000;
    my $rh_nid = $dbh->selectall_hashref("select id from node", "id");
    foreach my $nid (sort keys %{$rh_nid}) {
        ++$n_node;
        # this does the full matrix; in reality only need upper or lower half
        # also need to join with the renumbered ID table
        my $ra_nodes = $dbh->selectall_arrayref(
               "select distinct(B.nid) from element_node A, element_node B "  
               .   "where A.nid='$nid' and B.nid<>'$nid' and A.eid=B.eid "
               );
        $n_NNZ += scalar @{$ra_nodes};
        if (!($n_node % $SET_SIZE)) {
            $end_ti = time;
            printf "# node joins: %9d  (%.2f node/sec)\r", 
                    $n_node, $SET_SIZE/($end_ti - $start_ti);
            $start_ti = $end_ti;
        }
    }
    $st = $dbh->disconnect;
    my $end_t = time;
    printf "# node joins: %9d\n", $n_node;

    printf "Data extraction for %d nodes in %.2f sec  (%.2f node/sec)\n",
            $n_node, ($end_t - $start_t), $n_node/($end_t - $start_t);
    printf "The g set matrix will have %d non-zeros.\n", 6**2 * $n_NNZ;
# 1}}}
} elsif ($opt_r) { # renumbered node-node connectivity  {{{1
    my $start_t  = time;
    my $start_ti = time;  # interval timings
    my $end_ti   = 0;     # interval timings
    my $ra_n_nodes = $dbh->selectall_arrayref(
        "select max(seq_no) from node;");
    my $nNodes     = $ra_n_nodes->[0][0];

    # The select below returns connectivity of the renumbered matrix.
    # Diagonal terms and terms above the diagonal are omitted.
    # The pair  A,B  means the node whose renumbered seq_no is A is
    # attached to the node whose renumbered seq_no is B.
    my $ra_connectivity = $dbh->selectall_arrayref(
        "select R1.new_id, R2.new_id from node_connectivity C  , " .
                                         "renumbered_nid    R1 , " .
                                         "renumbered_nid    R2 "   .
           "where  R1.orig_id  =  C.nid_a and "  .
                  "R2.orig_id  =  C.nid_b and "  .
                  "R1.new_id  <=  R2.new_id "    . # omit to get upper half too
           "order by R1.new_id, R2.new_id; "                               
           );
#print Dumper($ra_connectivity);
    my $n_NNZ = scalar @{$ra_connectivity} + $nNodes; # add in diagonal terms

    $st = $dbh->disconnect;
    my $end_t = time;

    printf "Renumbered connectivity join in %.2f sec\n",
            ($end_t - $start_t);
    printf "Lower half of g set matrix will have %d non-zeros\n", 6**2 * $n_NNZ;
    printf "%d nodes, %d node-node connections, %.2f average interconnects\n", 
            $nNodes, $n_NNZ, ($n_NNZ - $nNodes)/$nNodes;
}
# 1}}}
