# Library functions for the scripting library (scrib)
#
# File: scrib/lib/uns.tcl
#
# $Revision$ on $Date$
# 
# Copyright (c) 1993-2003 ICEM CFD Engineering
#
#--------------------------------------------------------------------
#
# --> if the name of the first proc already exists in interp, return
#
if {"" != [info commands scrib_lib_uns_reorient_normals_family]} { return }
#
# --> procs in this file depend on the following scrib/lib/ files--source them
#     I guess we could do this by proc, too, not sure waht's best
#
if {"" != [info commands scrib_lib_setup_source_files]} {
    set required_files "catia assembly exec"
    scrib_lib_setup_source_files $required_files
}
#
#------------------------------------------------------------------------

## orient all surface element normals of current mesh by family <em>f</em>.

proc scrib_lib_uns_reorient_normals_family {f} {    
    #
    # first make a family-map of the family
    #
    set fammap [ic_uns_subset_create]
    ic_uns_subset_add_families_and_types $fammap $f QUAD_4
    ic_uns_subset_add_families_and_types $fammap $f TRI_3
    #
    # get the elements from that family-map
    #
    set els [ic_uns_subset_list_elements $fammap]
    if {"" != $els} {
	#
	# get the first element from that family-map
	#
	set el1  [lindex $els 0]
	set type [lindex $el1 0]
	set num  [lindex $el1 1]
	#
	# put that element in a subset: elemmap
	#
	set elemmap [ic_uns_subset_create]
	ic_uns_subset_add_number $elemmap $num 1 $type
	#
	# then orient the fammap wrt that elemmap
	#
	ic_uns_reorient $fammap consistent $elemmap
	#
	# delete the elemmap
	#
	ic_uns_subset_delete $elemmap
    }
    #
    # delete the fammap
    #
    ic_uns_subset_delete $fammap
}

## reorient the normals in the currently loaded mesh

proc scrib_lib_uns_reorient_normals {} {
    #
    # foreach family in the current mesh
    #
    foreach f [ic_uns_list_families] {
	scrib_lib_uns_reorient_normals_family $f
    }
}

## Reorient the given map to be consistently probably in the given direction

proc scrib_lib_uns_reorient_map_consistently_in_direction {name dir} {
    #
    # --> check the given subset name
    #
    if ![ic_uns_subset_exists $name] {
	mess "Warning: cannot reorient map $name consistent in dir: no such map exsits!\n"
	return 0
    }
    #
    # --> check the given dir
    #    
    if ![scrib_lib_math_is_point $dir] {
	# if it's something like "y-", translate that to {0 -1 0}
	set tdir [scrib_lib_math_std_unit_vector $dir]
	if [scrib_lib_math_is_point $tdir] {
	    set dir $tdir
	} else {
	    mess "Warning: cannot reorient map $name consistent in dir: bad direction $dir!\n"
	    return 0
	}
    }
    #
    # --> try to get a representative element from the mesh, one near the centroid
    #
    set bb [ic_uns_subset_bbox $name]
    set bmin [lindex $bb 0]; set bmax [lindex $bb 1]
    set cent ""
    foreach i {0 1 2} {
	lappend cent [expr {([lindex $bmin $i] + [lindex $bmax $i]) / 2.0}]
    }    
    set refmap [ic_uns_subset_create]
    set dims "2"
    set stat [ic_uns_subset_add_near_pos $refmap $cent $dims]
    #
    # --> re-orient that element to the given direction
    #    
    set stat [ic_uns_reorient $refmap dir $dir]
    #
    # --> re-orient the rest of the map with that element
    #
    set stat [ic_uns_reorient $name consistent $refmap]
    
    set norm [ic_uns_subset_normal $refmap]
    mess "Reoriented subset $name for consistent normal wrt an element with normal $norm\n"    
    
    ic_uns_subset_delete $refmap
    return 1
}

#------------------------------------------------------------------------

## load all mesh files from the directory <em>dir</em> (default pwd) with
## the filename extension <em>extension</em>.

proc scrib_lib_uns_load_dir {{dir ""} {extension uns}} {
    #
    # if dir specified, go there
    #
    if {"" != $dir} {
	set orig_dir [pwd]
	cd $dir
    }
    #
    # foreach file with the proper file extension
    #
    set fam_pid_map ""
    set loaded_files ""
    foreach f [glob -nocomplain -type f *$extension] {
     	#
	# get the pid from the filename, note this assumes catia
	#
	set pid [scrib_lib_catia_file_pid_get [file root $f]]
	#
	# load the mesh
	#
	ic_uns_load $f
	#
	if [ic_uns_is_loaded] {
	    #
	    # and rename all families to FAM_$pid
	    #
	    foreach fam [ic_uns_list_families] {
		if {$fam != "ORFN"} {
		    lappend fam_pid_map "$fam $pid"
		}
	    }
	    lappend loaded_file $f
	}
    }
    foreach {fam pid} $fam_pid_map {
	ic_uns_rename_family $fam [scrib_lib_assembly_famname_get $pid]
    }    
    #
    # cd back to the directory in which we began
    #
    if {"" != $dir} {
	cd $orig_dir
    }
    
    mess "loaded & merged files: $loaded_files\n"
    return $loaded_files
}

#------------------------------------------------------------------------

## load mesh files with filename ending <em>mesh_extension</em> from the
## <em>mesh_dir</em> (defaults to <em>cad_dir</em>) corresponding to files
## of the type <em>cad_sys</em> in the direcetory <em>cad_dir</em>. if
## the file <em>savefile</em> is specified, then the resultant uns object
## will be saved to that path and unloaded.

proc scrib_lib_uns_load_files {cad_sys cad_dir {mesh_dir ""} {mesh_extension ".uns"}\
	{savefile ""}} {
    #
    # get the list of cad_files
    #
    set cad_extension ".[scrib_lib_geo_cadsys_extension_get $cad_sys]"
    set cad_files [glob -nocomplain -type f [file join $cad_dir *$cad_extension]]
    #
    # if dir specified, go there
    #
    if {"" != $mesh_dir} {
	set orig_dir [pwd]
	cd $mesh_dir
    }
    #
    # foreach file with the proper file extension
    #
    set potential_mesh_files ""
    foreach cf $cad_files {
	#
	# use the mesh_extension given
	#
	set f "[file root [file tail $cf]]$mesh_extension"
	#
	# since mesh_extension may be something like "${part}_offset.uns"
	# and that file may not exist, try to get and load a "${part}.uns"
	# i think this is strange, but...
	#
	set altf "[file root [file tail $cf]].uns"
	if [file exists $f] {	
	    lappend potential_mesh_files $f	    
	} elseif {[string compare $f $altf] && [file exists $f]} {
	    lappend potential_mesh_files $altf
	}
    }
    #    
    #
    if {"" == $potential_mesh_files} {
	mess "found no domain files in [pwd] to load...returning.\n"
	return -1
    }
    mess "trying to load mesh files: $potential_mesh_files\n"
    #
    # first load all the files getting their families into the correct fpid
    #    and then unload them
    #
    set loaded_files ""
    foreach f $potential_mesh_files {
     	#
	# get the pid from the filename, note this assumes catia
	#
	set fpid [scrib_lib_catia_file_pid_get [file root $f]]
	#
	# load the mesh
	#
	ic_uns_load $f
	#
	# and rename all families to FAM_$pid
	#
	foreach fam [ic_uns_list_families] {
	    if {$fam != "ORFN"} {
		set targ_fname [scrib_lib_assembly_famname_get $fpid]
		ic_uns_rename_family $fam $targ_fname
	    }
	}
	lappend loaded_file $f
	
	ic_unload_mesh
    }
    #
    # now reload them all together with their correc fpids
    #
    foreach f $loaded_file {
	ic_uns_load $f
    }
    mess "loaded & merged files: $loaded_files\n"
    #
    # if savefile is specifed, save the meshobj and unload it
    #
    if {("" != $savefile) && [ic_uns_is_loaded]} {
	ic_save_unstruct $savefile
	ic_unload_mesh
	mess "scrib_lib_uns_load_files: saved uns file $savefile\n"
    }
    #
    # cd back to the directory in which we began
    #
    if {"" != $mesh_dir} {
	cd $orig_dir
    }    
    
    return 0
}

## unload and reload the current unstructured object. this is a work-a-round.

proc scrib_lib_uns_unload_reload {} {    
    
    if ![ic_uns_is_loaded] return
    
    set tfile "scrib_lib_uns_unload_reload.uns"
    ic_save_unstruct $tfile
    ic_unload_mesh
    ic_load_unstruct $tfile
    file delete $tfile
}

## quad_remesh the given mesh family <em>fam</em> along with
## <em>nlayers</em> around it.

proc scrib_lib_uns_remesh_byfam {fam {nlayers 0}} {
    
    if ![ic_uns_is_loaded] {
	mess "can't find current mesh...returning\n" red
    }
    if ![ic_uns_check_family $fam] {
	mess "can't find fam in current mesh...returning\n" red
    }
    #
    # should we try to project to geometry?
    #
    set projexists [expr {[ic_geo_is_loaded]}]
    if $projexists {
	mess "will project remeshing to loaded geometry\n" green
    } else {
	mess "cnnnot project remeshing to geometry; none loaded\n" red
    }
    #
    # create the subset
    # add the family--all element types
    # (add the layers)
    #
    set tmpmap [ic_uns_subset_create]
    ic_uns_subset_add_families_and_types $tmpmap $fam MIXED
    if {0 < $nlayers} {
	ic_uns_subset_add_layer $tmpmap $nlayers all all
    }
    #
    # make disconnected subsets of the tmpmap
    set diconnmaps [ic_uns_subset_into_connected_regions $tmpmap]    
    #
    # remesh each region; xxxx BEN/Ben/ben you should edit these
    # parameters!!!
    #
    foreach dm $diconnmaps {
	ic_uns_quad_remesh $dm complete_edges 0 merge_ends 0 \
		all_dim 0 element 2 proj $projexists \
		max_steps 100 ele_tol 0 \
		how 7 debug 0 dev 0 iters 20 make_consistent 0 \
		surf 0 conver 0.025 geo_active 0 merge_tol 0.10
	ic_uns_subset_delete $dm
    }
    ic_uns_subset_delete $tmpmap
}

## review a mesh and tetin file in med interactively.

proc scrib_lib_uns_review_interactive {file exec_args} {
    global proc_scrib_data
    #
    # --> make interactive at any cost
    #
    set new_exec_args ""
    foreach {n v} [scrib_lib_utils_strip_down_list $exec_args] {
	if {$n == "-interactive"} {
	    append new_exec_args " $n 1"
	} else {
	    append new_exec_args " $n $v"
	}
    }
    set exec_args $new_exec_args

    set exportfile [scrib_lib_export_filename_get $proc_scrib_data(export_dir) $file \
			$proc_scrib_data(export_extension)]   
    set script "mesh_review.tcl"
    set proc_scrib_data(batch_script) $script
    
    set job_token [scrib_lib_exec_get_unique_job_token [file tail [file root $file]]]
    set proc_scrib_data(name)         $file    
    set med_args ""
    return [scrib_lib_exec_medbatch $job_token "$script" $med_args $exec_args]

}

## clean up possible tempfiles from a directory

proc scrib_lib_uns_remove_tempfiles {{dir ""}} {
    
    if {"" != $dir} {
	set wdir $dir 
    } else {
	set wdir [scrib_lib_glue_get_working_directory]
    }
    #
    # --> clean out all temp files.  I know this is really bad, but currently if you delete files 
    #    after they are created in MED, I can't delete them... BEN.  Jason, maybe you can look at this?
    #
    foreach f {quad_only.uns partial_quad.uns tri.uns tri_mesh.uns \
		   tri_offset.uns tetra.tin tetra_cmd1.tmp tetra_cmd.log} {
	set tfile [file join $wdir $f]
	if [file exists $tfile] {
	    file delete $tfile
	    mess "file $tfile deleted\n"
	}
    }
}

## foreach domainfile in the directory, review it interactively.

proc scrib_lib_uns_review_interactive_dir {{idir ""}} {
    global proc_scrib_data

    if {[info exists proc_scrib_data(skipto)] && $proc_scrib_data(cad_selmethod) == "skipto"} \
	{set skipto $proc_scrib_data(skipto)} else {set skipto ""}    

    if 0 {
	# this is for the regression testing, but could be annoying to
	# user...not sure yet... --jka
	if {0 == $proc_scrib_data(interactive)} {	
	    stdout "application not in interactive mode...returning.\n" red
	    return
	}
    }
    
    if {"" != $idir} {
	set wdir $idir
    } else {
	set wdir [scrib_lib_glue_get_working_directory]
    }    
    #
    # --> clean out all temp files.
    #
    scrib_lib_uns_remove_tempfiles $wdir
    #
    # -->  User might want to skip to a certain file       
    #
    

    #
    set cmd "scrib_lib_uns_review_interactive"
    set files [scrib_lib_exec_foreach_file $cmd domain $wdir $wdir $skipto]    
    
    stdout "\nFinished reviewing meshed parts in med...\n"
}

## needs doc.

proc scrib_lib_uns_put_mesh_in_family {target_family} {
    if ![ic_uns_is_loaded] {
	mess "cannot change family of mesh, for no mesh is loaded\n" red
	return -1
    }
    foreach fam [ic_uns_list_families] {
	if {$fam != "ORFN"} {
	    ic_uns_rename_family $fam $target_family
	}
    }
    return 0
}

## needs doc.

proc scrib_lib_uns_get_nodes_between_fams {subset_name} {
    
    set node_fam_list ""
    
    foreach item [ic_uns_subset_list_elements $subset_name] {
	if {([lindex $item 0] != "TRI_3")  && ([lindex $item 0] != "QUAD_4")} {continue}
	set fam [lindex $item 3]
	foreach n [lindex $item 2] {
	    lappend node_fam_list [list $n $fam]
	}
    }
    
    set node_fam_list [lsort -unique $node_fam_list]
    set node_fam_list [lsort -index 0 $node_fam_list]
    #mess $node_fam_list blue
    
    set prev ""
    set return_nodes ""
    foreach i $node_fam_list {
	if {$prev == ""} {
	    set prev [lindex $i 0]
	    continue
	}
	if {[lindex $i 0] == $prev} {
	    lappend return_nodes $prev
	} else {
	    set prev [lindex $i 0]
	}
    }
    
    return $return_nodes
}

## procedure to get connected regions of bars
## returns a list of subset names of connected regions.
proc scrib_lib_uns_get_connected_bar_regions {subset_name} {
    
    set node_el_list "" 
    set el_nodes_list ""
    set el_list ""
    foreach item [ic_uns_subset_list_elements $subset_name] {
	if {([lindex $item 0] != "BAR_2") && ([lindex $item 0] != "LINE_2")} {
	    mess "There should not be any [lindex $item 0] elements in $subset_name.\n" red
	    continue
	}
	set el [lindex $item 1]
	foreach n [lindex $item 2] {
	    lappend node_el_list [list $n $el]
	}
	lappend el_list $el
	lappend el_nodes_list [list $el [lindex $item 2]]
    }
    
    set el_nodes_list [lsort -index 0 $el_nodes_list]
    set node_el_list [lsort -index 0 $node_el_list]
    
    #mess $node_el_list cyan
#reorganize node_el_list to node_els_list with the grouped els based off nodes.
    set node_els_list ""
    set prev ""
    set prev_el ""
    set return_nodes ""
    foreach i $node_el_list {
	if {$prev == ""} {
	    set prev [lindex $i 0]
	    set prev_el [lindex $i 1]
	    continue
	}
	if {[lindex $i 0] == $prev} {
	    lappend prev_el [lindex $i 1]
	    set doit 1
	} else {
	    lappend node_els_list [list $prev $prev_el]
	    set prev [lindex $i 0]
	    set prev_el [lindex $i 1]	
	    set doit 0
	}
    }
    if $doit {
 	lappend node_els_list [list $prev $prev_el]
    }
#set variables from lists
    foreach en $el_nodes_list {
	set e [lindex $en 0]
	set n [lindex $en 1]
	set nodes($e) $n
    }
    foreach ne $node_els_list {
	set n [lindex $ne 0]
	set e [lindex $ne 1]
	set elems($n) $e
    }
#mess "el_nodes_list is $el_nodes_list\n" blue
#mess "node_els_list is $node_els_list\n" blue
#Now find the connections...
    set list_of_subsets ""
    set used_el_list ""
    set Q ""
    set i 0
    while [llength  $el_list] {

	if {[llength $Q] == 0} { 
	    set Q [lindex $el_list 0]
	    incr i
	    set subs($i) ""
	    if {$i > 1} {
		set ii [expr $i - 1]
	    	lappend list_of_subsets $subs($ii)
	    }
	}
	if {$Q == ""} break
	set el [lindex $Q 0]
	#mess "el is $el\n" green
	lappend subs($i) $el
	lappend used_el_list $el
	set pos [lsearch $el_list $el]
	set el_list [lreplace $el_list $pos $pos]
	#mess "Q is $Q\n" red
	set Q [lreplace $Q 0 0]
	set used ""
	foreach n $nodes($el) {
	    if ![info exists elems($n)]  {
		mess "no info for elems($n)\n" red
	    } else {
	    	set used [concat $used $elems($n)]
	    }
	}
	#mess "used is $used \n" grey
	set used [lsort -unique $used]
	foreach u $used {
	    if {[lsearch $used_el_list $u] == -1} {
		lappend Q $u
	    }
	}
	#mess "el_list is $el_list\n" red
    }
#mess "list of subsets is $list_of_subsets\n" 
#We have a list of lists, now we need to put these into subsets
    set f 1
    set list_of_sub ""
    foreach ll $list_of_subsets {
	set s($f) [ic_uns_subset_create]
	lappend list_of_sub $s($f)
	#mess "ll is $ll\n" red
	foreach l $ll {
	    if [scrib_lib_exec_running_aienv] {
	    	ic_uns_subset_add_number $s($f) "$l" 1 LINE_2
	    } else {
	    	ic_uns_subset_add_number $s($f) "$l" 1 BAR_2 
	    }
	}
	incr f
    }
    return $list_of_sub
}

## needs doc.

proc scrib_lib_uns_subset_get_nodes {subset_name} {
    set nodes ""
    foreach item [ic_uns_subset_list_elements $subset_name] {
	set nodes [concat $nodes [lindex $item 2]]
    }
    set nodes [lsort -unique $nodes]
    return $nodes
}

proc scrib_lib_uns_number_type {subset_name type} {
    set num 0
    foreach item [ic_uns_subset_list_elements $subset_name] {
	if {[lindex $item 0] == $type} {incr num}
    }
    return $num
}










