# Library functions for the scripting library (scrib)
#
# File: scrib/lib/tetra.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_tetra_partial_mesh]} { 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 0 {
# can't do this because quad includes tetra includes quad...
    if {"" != [info commands scrib_lib_setup_source_files]} {
	set required_files "utils quad"
	scrib_lib_setup_source_files $required_files
    }
}

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

##  Find perim curves for common surfaces between failed mesh and good mesh.

proc scrib_lib_tetra_find_perim_curves { bad_surfs } {
    set temp_perim_curves ""
    foreach surf $bad_surfs {
	set temp_perim_curves [concat $temp_perim_curves [ic_geo_boundary surface $surf 0 1]]
    }
    set temp_perim_curves [lsort -unique $temp_perim_curves]
    set perim_curves ""
    foreach curve $temp_perim_curves {
	foreach isurf [ic_geo_incident curve $curve 1] {
		if {[lsearch -exact $bad_surfs $isurf] == -1} {lappend perim_curves $curve	}
	}
    }
    return $perim_curves 
}


##  partial tet mesher
##  this will save good surfs to good_surfs.tin

proc scrib_lib_tetra_partial_mesh { bad_surfs failed_loops quad_args {mesh_size ""} {error 0} } {

    #---->File names
    set goodloopstin good_loops.tin
    set badsurfstin bad_surfs.tin
    set badsurfsuns tri_mesh.uns
    set partial_quaduns partial_quad.uns
    set tetra_log tetra_cmd.log

    #we will save the domain file.  If the tetra->quad with mesh boundaries does not work, 
    #we could try to use the tri_mesh.uns and partial_mesh.uns and merge boundaries.	
    ic_save_unstruct $partial_quaduns
    if [ic_uns_is_loaded] { ic_unload_mesh }
    #
    #--> Save a good tetin for partial meshing after tetra is run
    #
    ic_delete_geometry loop names $failed_loops
    set perim_curves [scrib_lib_tetra_find_perim_curves $bad_surfs]   
    ic_geo_set_family curve COMMON names $perim_curves ; #this shouldn't be necessary
    ic_save_tetin $goodloopstin

    #
    #--> Now prepare file for Tetra
    #
    #It would be nicer here, if we had an option to just save bad surfaces (and those curves/points attached)
    #to a tetin file, and just run Tetra on this local tetin file.  It would also be nice to not have to force the perim_curves to a special part.  
    mess "bad surfs are $bad_surfs, perim curves are $perim_curves\n" blue
    foreach s [ic_geo_get_objects surface ""] {
	if {[lsearch -exact $bad_surfs $s] == -1} {ic_delete_geometry surface names $s}	
    } 
    ic_delete_geometry loop all ""
    ic_geo_delete_unattached
    if {$mesh_size == ""} {set mesh_size [lindex [ic_get_meshing_params curve [lindex [ic_geo_get_objects curve COMMON] 0] ] 1] }
    ic_set_meshing_params surface_all {} emax $mesh_size
    #
    #-->Tetin file for Tetra
    #
    ic_save_tetin $badsurfstin
    catch {ic_run_tetra $badsurfstin $badsurfsuns run_cutter 1 auto_orphan 0 \
	    fix_non_manifold 0 run_smoother 1 write_volume 0 smoother_n_iter 0 \
	    smoother_aspect 0.4 run_coarsener 0 coarsen_aspect 0.1 n_processors 4 \
	    save_all_triangles 1 log $tetra_log}

    if ![ic_load_unstruct $badsurfsuns] {	
	#maybe it is best to just ignore any bad geometry if we can't load a domain file. 
	#it appears that this fails due to having small surfaces that would be negligible,
	#and thus no nodes or elements
	mess "partial tet meshing did not generate a valid $badsurfsuns file, \
		assuming we can ignore geometry"
	mess "Was not able to load domain file.  Assuming this is due to having no valid mesh.\n" red
	if [ic_uns_is_loaded] { ic_unload_mesh }
    } else {
	if {0 >= [ic_count_nodes]} {
	    mess "Error mesh $badsurfsuns has no nodes...stopping scrib_lib_tetra_partial_mesh\n" red
	    return 1
	}
    }    
    #if quad_args element is 2 we need to run tri2quad
    set el [lsearch $quad_args element]	
    set el_val [lindex $quad_args [expr $el + 1]]
    set pr [lsearch $quad_args proj]	
    set proj [lindex $quad_args [expr $pr + 1]]

    if [ic_uns_is_loaded] {
	if {($el_val == 2) || ($el_val == 1)} {
	    ic_change_tri_quad_2 all $proj 0 0 -1 160 20 0
	} elseif {$el_val == 4} {
	    ic_change_tri_quad_2 all $proj 0 0 -1 160 20 1
	}
    }         
    #
    # tetra mesh is generated, now merge in quad.----------------------
    #
    ic_unload_tetin
    ic_load_tetin [list "$goodloopstin"]
    #
    #now cleanup files generated
    #
    foreach f [concat [ list $badsurfsuns $badsurfstin $goodloopstin $partial_quaduns ] [glob -nocomplain tetra_cmd* ] ] {
	if ![file exists $f] continue
	file delete $f
    }
    #    

    if {1 == $error} {
	if {[ tk_dialog .tetra_done "Tetra finished" "Continue to quad?"  \
			    "" -1 Yes No ]}  {return ""}
    }

    #make sure all elements projected to curves are in common part
    if [ic_uns_is_loaded] {
	foreach c [ic_geo_get_objects curve COMMON] {
	    set ss [ic_uns_get_attached_elements curve $c ss]
	    ic_uns_set_part $ss COMMON
	    ic_uns_subset_delete $ss
	}
    }

    set rerun_quad_with_loop_mesh_boundaries 1
    if $rerun_quad_with_loop_mesh_boundaries {
	#force nodes to follow bunching for quad
	if [ic_uns_is_loaded] {
	    set p [lsearch $quad_args bunch]
	    if {$p > -1} {set quad_args [lreplace $quad_args $p [expr $p + 1]]}
	    lappend quad_args bunch 1
	}
	#make sure error family is being used
	set e [lsearch $quad_args error_family]
	if {$e == -1} {
	    set error_family ERROR
	    lappend quad_args error_family $error_family 
	} else {
	    set error_family [lindex $quad_args [expr $e + 1]]
	}
	#need to replace loops arg with current loops since we have deleted some.
	set l [lsearch $quad_args loops]
	if {$l > -1} {set quad_args [lreplace $quad_args $l [expr $l + 1]]}
	set new_loops [ic_geo_get_objects loop ""]
	if {$new_loops != ""} {
		lappend quad_args loops $new_loops
		if [catch {eval ic_quad $quad_args} res ] {
			mess "$res\n" red
			set err 4
		}
	}
	set new_failed_loops [ic_geo_get_objects loop $error_family]
    }
    #merge partial approach would be to take quad mesh, and mesh from tetra and stitch edges
#    set merge_partial 0
#    if $merge_partial {
#    	ic_uns_load partial_quad.uns
#    	#Now maybe we could merge families COMMON and ERROR
#    	set junkmap [ic_uns_subset_create junk]
#    	ic_uns_subset_add_families_and_types $junkmap ERROR {BAR_2 LINE_2}
#    	ic_uns_subset_add_families_and_types $junkmap COMMON {BAR_2 LINE_2}
#    	ic_uns_quad_remesh $junkmap complete_edges 0 merge_ends 0 \
#		all_dim 0 element 3 proj 0 max_steps 100 ele_tol 0 how 4 \
#		debug 0 dev 0 iters 20 make_consistent 0 surf 0 conver 0.025 \
#		geo_active 1 merge_tol 0.10
#	ic_uns_subset_delete $junkmap
#    	set q_error 0
#    }
#    if {$q_error == 1} {
#	mess "need to mesh with pure tet method"
#	if [scrib_lib_tetra_mesh] {
#	    mess "There was an error in scrib_lib_tetra_mesh\n" red
#	    return 1
#	} else {set q_error 0}
#    }    
#    if 0 {
#	# clean up tri.uns and tri_mesh.uns temp mesh files...xxxxxx
#	if {[] && []} {
#	    ic_rm $tmpmesh
#	} else {
#	    mess "not delete "
#	}
#    }
    return $new_failed_loops
}

## tet mesher. needs doc.

proc scrib_lib_tetra_mesh { } {
    global proc_scrib_data
    #global q_error
    

    if ![ic_geo_is_loaded] {
	mess "scrib_lib_tetra_mesh called w/o geomobj" red
	return
    }
    if [ic_uns_is_loaded] { ic_unload_mesh }
    #
    # set some meshing parameters
    #    
    ic_build_topo $proc_scrib_data(build_topo_tol) -angle 30 -filter_curves -filter_points
    ic_set_meshing_params surface_all {} emax $proc_scrib_data(mesh_size)
    ic_set_meshing_params global 0 gref 1 gmax 100
    #
    # the following would not be necessary if Tetra for surface mesh did not need mat pt.
    #
    ic_geo_create_material_location LIVE {0 0 0}
    #
    # save the tetin file
    #
    set tetinwmat tetra.tin
    ic_save_tetin $tetinwmat
    #
    # run tetra for the mesh
    #
    set trimesh tri.uns
    catch {ic_run_tetra $tetinwmat $trimesh run_cutter 1 auto_orphan 0 \
	    fix_non_manifold 1 run_smoother 1 write_volume 0 smoother_n_iter 0 \
	    smoother_aspect 0.4 run_coarsener 0 coarsen_aspect 0.1 n_processors 4 \
	    log tetra_cmd.log}
    
    ic_load_unstruct $trimesh
    if {0 >= [ic_count_nodes]} {
	mess "Error mesh $trimesh has no nodes...stopping scrib_lib_tetra_mesh\n" red
	return 1
    }
    
    set q_error 0
    if [ic_uns_is_loaded] {
	ic_uns_merge_nodes all $proc_scrib_data(ignore_tol)
	ic_uns_swap_edges_auto all 0 10
	#
	# if loaded, delete the trimesh! right? --jka
	#
	ic_rm $trimesh
    } else {
	set q_error 1
    }
    
    return $q_error
}





