# Script file for the scripting library (scrib)
#
# File: scrib/scripts/mesh_quad.tcl
#
# $Revision$ on $Date$
# 
# Copyright (c) 1993-2003 ICEM CFD Engineering
#
#--------------------------------------------------------------------

#set debug 1
set x [clock seconds]
#
# set local variable for global variable by addind a "V_"
#
set V_model $proc_scrib_data(model)
set proc_scrib_data(name) [file rootname $V_model]

#I don't think we should need dir anymore, this should be wdir now...  BEN
#if ![info exists proc_scrib_data(dir)] {
#    if [info exists proc_scrib_data(wdir)] {
#	set proc_scrib_data(dir) $proc_scrib_data(wdir)
#    } else {
#	set proc_scrib_data(dir) [pwd]
#    }
#}
foreach nm [array name proc_scrib_data] {
    if [info exists proc_scrib_data($nm)] { 
	set V_$nm $proc_scrib_data($nm) 
#	mess "V_$nm is $proc_scrib_data($nm) \n"
    }
}

# Read special meshing params from file
#
#this should probably get moved out to seperate proc... BEN
if ![info exist V_file_check] {set V_file_check 0}
if {$V_file_check == 1} {
   set prt_nm_lst ""
   if {[file isfile $V_spcl_file] == 1 && [file extension $V_spcl_file] == ".csv"} {
     set f [open $V_spcl_file "r"]
     gets $f txt
     set var_nm [lrange [split $txt ,] 1 end]
     foreach var $var_nm {lappend var_nm_lst [lindex [split $var " "] 0]}
     set var_ln [llength $var_nm_lst]
     while {[gets $f txt] >= 0 } {
        if {[string first "\#" $txt] == 0} continue
        if {[string first "\"" $txt] == 0} continue
        set prt_nm [lindex [split $txt ,] 0]
        if {$prt_nm == ""} continue
        set var_vl [lrange [split $txt ,] 1 end]
        if {$var_ln == [llength $var_vl]} {
           lappend prt_nm_lst $prt_nm
           lappend var_vl_lst $var_vl
        }
     }
     close $f
   }
   for {set i 0} {$i < [llength $prt_nm_lst]} {incr i} {
      set prt [lindex $prt_nm_lst $i]
      if {[string first $prt $V_name] == -1} continue
      set var_vl [lindex $var_vl_lst $i]
      for {set j 0} {$j < [llength $var_nm_lst]} {incr j} {
         set nm [lindex $var_nm_lst $j]
         set vl [string trim [lindex $var_vl $j]]
         if {$vl != ""} {set V_$nm $vl}
      }
   }
}

#SET DEFAULTS
if ![info exists V_interactive] {set V_interactive 0}
if ![info exists V_failure_mode] {set V_failure_mode 0}

if {![file exists $V_model] && ("relative" == [file pathtype $V_model])} {
    set V_cadfile $V_cad_dir/$V_model
} else {
    set V_cadfile $V_model
}
if ![info exists V_thickness] {set V_thickness 0}
if ![info exists V_export_dir] {
    set V_export_dir "."
} elseif ![file isdirectory $V_export_dir] {
    file mkdir $V_export_dir
}

#SET DEFAULT TEMPORARY FILE NAMES
set interim_mesh  [file join $V_wdir [file tail ${V_name}]].uns
set interim_geom  [file join $V_wdir [file tail ${V_name}]].tin
set meshable_geom [file join $V_wdir [file tail ${V_name}]]_meshable.tin
set offset_mesh   [file join $V_wdir [file tail ${V_name}]]_offset.uns
set offset_geom   [file join $V_wdir [file tail ${V_name}]]_offset.tin
set thisextrude_tetin [file join $V_wdir [file tail ${V_name}]]_extrude.tin
set out_boco      [file join $V_wdir [file tail ${V_name}]].fbc
set export_file [file join $V_export_dir [file tail ${V_name}]].nas

# -------- end of setup -----------

#
# --> get the nastran pid from this cad part file name if possible
#

set V_naspid [scrib_lib_glue_assembly_filename_naspid_get [file tail $V_name]]
if {1 == $V_naspid} {
    mess "Warning: could not get a nastran pid from the filename $V_name. \
                    Please check your nastran pid settings\n" red
    set badnaspid 1
}

mess "Nastran Shell pid for file $V_name is $V_naspid\n" blue

set thisscript_fam [scrib_lib_assembly_famname_get $V_naspid]

#
# --> import the cad file to a tetin
#
cd $V_wdir

switch $V_cadsys {
    catia {
	if [info exists V_layers] {	    
	    scrib_lib_catia_import $V_cadfile $interim_geom $V_layers
	    scrib_lib_utils_putdebug "Loading tetinfile $interim_geom...\n"
	    ic_load_tetin [list "$interim_geom"]
	    
	    if ![llength [ic_geo_get_objects surface ""]] {
		mess "no surfaces in layers $V_layers trying noshow area\n" red
		ic_unload_tetin
		scrib_lib_catia_import $V_cadfile $interim_geom $V_layers 0 1
		scrib_lib_utils_putdebug "Loading tetinfile $interim_geom...\n"
		ic_load_tetin [list "$interim_geom"]
	    }
	    
	} else {	    
	    scrib_lib_catia_import $V_cadfile $interim_geom
	}
    }
    default {
	#
	# try a more general command
	#
	set command "scrib_lib_${V_cadsys}_import"
	if {$command == [info commands $command]} {
	    $command $V_cadfile $interim_geom
	} else {
	    mess "Error: CAD system \"$V_cadsys\" not supported. cannot get command $command" red
	    return
	}
	#
	#
	# --> load the tetin
	#
	mess "Loading and verifying Tetin file [file tail $interim_geom]...\n\n"
	ic_load_tetin [list "$interim_geom"]

	ic_delete_geometry curve names [ic_geo_get_objects curve ""]
	ic_delete_geometry point names [ic_geo_get_objects point ""]

    }
}
#
#--> check to make sure a tetin file is loaded
#
if ![ic_geo_is_loaded] {
    mess "No tetin is loaded, stopping." red
    return
}
#
#============ CHECK IF EMPTY =========================
#
# --> check to see that there are surfaces in the layers
#
if ![llength [ic_geo_get_objects surface ""]] {
    set place $V_name
    if [info exists V_layers] {
	append place " in layers $V_layers"
    }
    mess "Error: no surfaces in $place...returning\n" red
    #
    ## xx ?? note nastran specificity xx ## ??
    set n [open [file join $V_export_dir [file tail $V_name]]_no_surfs.nas "w"]
    puts $n "no surfaces in $place\n"
    close $n
    return
}

#========== BUILD TOPO =======================

mess "Building topology...\n\n"

ic_set_meshing_params global 0 gref 1 gmax 64
#ic_geo_fixup 1
#ic_build_topo $V_build_topo_tol -angle $V_ignore_angle -filter_points
ic_build_topo $V_build_topo_tol
ic_build_topo [expr $V_build_topo_tol * 4] -only_singles
ic_geo_delete_unattached 
#if [catch {ic_geo_surface_create_smart_nodes [ic_geo_get_objects surface ""] $V_mesh_size $V_build_topo_tol} res] {
#    mess "Error: $res\n" red
#}
#ic_build_topo $V_build_topo_tol
#ic_geo_delete_unattached
#mess "curves after ic_geo_delete_unattached: [ic_geo_get_objects curve ""]\n"

#
#============ CHECK IF SOLID ELSE OFFSET =========================
# --> check to see if the object is a solid (has no single edges), if so, move file to wdir/solid_parts
#

mess "Checking for solid part...\n"

set no_single 1
foreach curve  [ic_geo_get_objects curve ""] {
    if {[ic_geo_crv_length $curve] < $V_ignore_tol} continue
    if {[llength [ic_geo_incident curve $curve]] == 1} {
	set no_single 0
	break
    }
}
if $no_single {
   if ![info exists V_Solid_Method] {set V_Solid_Method 0}

    if {$V_Midsurface_Method == 0} {
	set V_mid_surf_max_dist [expr [ic_geo_default_topo_tolerance] * 10 ]
	mess "Auto Tolerance set to $V_mid_surf_max_dist\n"
    }
    foreach p [ic_geo_list_parts] {
	if {[ic_geo_get_objects surface $p] == ""} continue
	set solid [scrib_lib_geo_get_solid_type $V_mid_surf_max_dist $p 1]
	set solid_type [lindex $solid 0]
	switch $solid_type {
	    solid {
		mess "Thick solid found.\n" red
	    }
	    thin_solid {
		set V_Solid_Method 3
		set V_thickness [lindex $solid 1]
		set surf_groups [lindex $solid 2]
		mess "Thin solid found.\n" red
	    }
	    default {
		mess "solid definition getting set improperly; solid is $solid\n" red
		return
	    }
	}
    }

    if $V_interactive { scrib_lib_exec_med_display_update }

    if {1 == $V_failure_mode} {
	if {[ tk_dialog .solid_model "Found Solid Model" \
	      "Do you want to proceed?" "" -1 Yes No ]}  {
	    return
	}
    }

   switch $V_Solid_Method {
    	0 {
    	    mess "There are no single edges, so assuming this is a solid\n" red
	    set solid_file $V_wdir/solid_parts/
	    if ![file exists $V_wdir/solid_parts] {
		file mkdir $V_wdir/solid_parts
	    }
 	    append solid_file [file tail $V_cadfile]
	    if ![file exists $solid_file] {file copy $V_cadfile $solid_file}
    	    #
	    set n [open [file join $V_export_dir [file tail $V_name]]_no_surfs.nas "w"]
    	    puts $n "There are no single edges in $V_name, so assuming this is a solid\n"
    	    close $n
    	    return
    	}
    	1 {
	    mess "Solids will Be surface meshed\n" green
    	}
	2 {
	    mess "Solids will be Tetra Meshed ... \n" green
	    ic_set_meshing_params surface_all {} emax [expr $V_mid_surf_max_dist / 2]
	    foreach o [ic_geo_get_objects material] {
		ic_delete_geometry material names $o
	    }
	    ic_save_tetin $meshable_geom
	    ic_run_tetra $meshable_geom $interim_mesh run_cutter 1 run_smoother 0 n_processors 1 in_process 1 auto_vol 1 log junk.log
	    ic_uns_coarsen all 0.2 {} 0 5 1 0 $V_mesh_size
	    ic_uns_renumber_all_nodes 1 1
	    ic_uns_renumber_all_elements 1 1
	    ic_save_unstruct $interim_mesh 1 {} {} {} {} 0
	    scrib_lib_output_thickness_set_nastran $thisscript_fam \
		$V_naspid $V_thickness $out_boco 1
	    return
    	}
	3 {
	    if ![info exists V_mid_surf_keep_orig] {set V_mid_surf_keep_orig 0}
	    if {$V_mid_surf_keep_orig == ""} {set V_mid_surf_keep_orig 0}
	    
	    mess "Solids will be attempted to be compressed.\n" green
	    if $V_mid_surf_variable_thickness {
		set sss [ic_geo_get_objects surface ""]
		set args [list max_dist $V_mid_surf_max_dist family $thisscript_fam \
		    surfaces $sss save_old $V_mid_surf_keep_orig \
		    ask 0 partial 0 similar 1 precision 0]
mess "args are $args\n"
	       eval ic_geo_midsurface $args
	    
		if {[ic_geo_get_objects surface $thisscript_fam] == ""} {
		    mess "There are no surfaces left after midsurfacing!!!\n \
                                Either midsurfacing did not perform correctly, or you need to use a larger Max distance.\n \
		                Please use Info->distance to figure out a better distance to use, and restart.\n" red
		    return
		}
		#now we need to set the thickness...
		set V_thickness [scrib_lib_geo_average_thickness $thisscript_fam]
		mess "thickness is found to be $V_thickness\n"

	    } else {
		set base [lindex [scrib_lib_geo_sort_by_srf_area $surf_groups] end]
		foreach b $base {ic_geo_subset_add_items OFFSET  [list surface $b]}
		if [llength [info commands aie_getBatchGeomDisplay]] {aie_getBatchGeomDisplay}
		ic_save_tetin temp.tin
		if [catch {
		    ic_geo_cre_srf_offset $thisscript_fam "" $base [expr $V_thickness / 2] 0 1
		} res ] {
		    mess "failed in offsetting.  Will just mesh largest area not offset\n" red
		    ic_unload_tetin 
		    ic_load_tetin temp.tin
		    ic_geo_set_family surface $thisscript_fam names $base 0
		}

	    } 
	    if $V_interactive { scrib_lib_exec_med_display_update }

	    if {1 == $V_failure_mode} {
		if {[ tk_dialog .midsurface_done "Midsurfacing Done" \
		      "Do you want to proceed?" "" -1 Yes No ]}  {
		    return
		}
	    }
		
	    if $V_mid_surf_keep_orig {
		    ic_build_topo $V_build_topo_tol $thisscript_fam
		    set free_surfs [ic_geo_get_objects surface $thisscript_fam]
	    } else {
		foreach sub [ic_geo_subset_list] {ic_geo_subset_delete $sub}
		foreach fam [ic_geo_list_families] {
		    if {$fam == "ORFN"} continue
		    if {$fam == $thisscript_fam} continue
		    ic_delete_geometry surface families $fam
		    ic_delete_geometry curve families $fam
		    ic_delete_geometry point families $fam
		}
		ic_build_topo $V_build_topo_tol 
	    }
   	}
    	default {
	    mess "no method defined for $V_Solid_Method\n" red	    
    	}
    }
} else {
#==================== OFFSET GEOMETRY ================
switch $V_offset {
    0 {
    #No offset
	mess "No offset defined. \n" red
    }

    1 {
    #From a file
	scrib_lib_tetin_get_thickness_from_file	
	set V_thickness $proc_scrib_data(thickness)
	set V_offset_dir $proc_scrib_data(offset_dir)
	set V_offset $proc_scrib_data(offset)
	if {![info exists V_thickness)] && \
	    ![info exists V_offset_dir)] } {
		mess "not enough data found for offset\n" red
		set V_offset 0
	} else {
	    if {($V_offset_dir == "NO") || ($V_offset_dir == "No")} {
		set V_offset_dir no
	    }
	    if {$V_offset_dir != "no"} {
#JASON WE NEED A ROUTINE LIKE THIS FOR GEOMETRY
		if [scrib_lib_uns_reorient_map_consistently_in_direction All $V_offset_dir] {
		# then it succeeded and we can offset by normal
		   set $V_offset_dir "normal"
		}
	    }
	}
    }

    2 {
   #From layers
	set stat 0
	switch $V_cadsys {
	    catia {
		set stat [scrib_lib_catia_import $V_cadfile \
		    $thisextrude_tetin $V_offset_layers 1]
	    }
	    default {
		mess "does not support cad system $cadsys"
		set stat 1
	    }
	}
#return
	if !$stat { 
#should not need next three lines, but it gets around bug #9865
	    ic_save_tetin junk.tin
	    ic_unload_tetin
	    ic_load_tetin junk.tin
	    ic_load_tetin [list "$thisextrude_tetin"]
	    set offset_curves [scrib_lib_geo_get_unattached_curves [ic_geo_get_objects curve ""]]
	    if [llength $offset_curves] {
		set thick_dir [scrib_lib_offset_find_offset_curve $thisscript_fam $offset_curves]
		if {[llength $thick_dir] != 2} {
		    mess "There is not proper information for offset.  \
			Thickness and direction are $thick_dir\n" red
		    return
		}
		set V_thickness [lindex $thick_dir 0]
		set V_offset_dir "normal"
		#mess "V_thickness is $V_thickness\n"
	    } else {
		mess "no curves in layers $V_offset_layers\n"
		return
	    }  
	} 
    }
    default {
	mess "offset $V_offset not defined\n" red
	return
    }
}
#
# --> PERFORM OFFSET  
#
    if [info exists V_offset_dir] {
	if $V_interactive { scrib_lib_exec_med_display_update }

	if {1 == $V_failure_mode} {
	    if {[ tk_dialog .offset "Proceed to offset" \
		      "Do you want to proceed to offset geometry?" "" -1 Yes No ]}  {
		return
	    }
	}
	if {$V_offset_dir != "no"} {
	    mess "Offsetting by thickness of $V_thickness, in dir $V_offset_dir\n" blue
	    set srfs [ic_geo_get_objects surface ""]
	    ic_geo_cre_srf_offset $thisscript_fam $thisscript_fam $srfs [expr $V_thickness / 2.0] 0 1

	    if $V_interactive { scrib_lib_exec_med_display_update }
	    if {1 == $V_failure_mode} {
		if {[ tk_dialog .offset "Offset done" \
		      "Do you want to proceed?" "" -1 Yes No ]}  {
		    return
		}
	    }
	    foreach s $srfs {
		if {[ic_geo_check_objects_exist surface $s] == ""} {mess "not finding surface $s\n" ; continue}
		ic_delete_geometry surface names $s
	    }
	    ic_geo_delete_unattached    
	    ic_build_topo $V_build_topo_tol
	} else {
	    mess "Not offsetting, but will assign thickness.\n" blue
	}
    }
}
#
#================ SET MESH SIZES.  ALSO PUT ALL SURFACES INTO PROPER PART NAME FOR ASSEMBLY ==============
#
    ic_set_meshing_params curve_all {} emax $V_mesh_size
    if {![info exists free_surfs] || ($free_surfs == "")} {
	ic_geo_set_family surface $thisscript_fam names [ic_geo_get_objects surface ""] 0
    }
#
#================ IF SUFFICIENT WELD INFORMATION, READ WELD FILE AND CREATE POINTS =========
#

if {[info exists proc_scrib_data(welding_file)] && [file exists $proc_scrib_data(welding_file)] && \
	[info exists proc_scrib_data(welding_mode)] && ("" != $proc_scrib_data(welding_mode))} {
        
    set mode $proc_scrib_data(welding_mode)
    set args "-shadow $V_naspid -report_file __none__ "
    
    if {[info exists proc_scrib_data(welding_maxproject)] && \
	    ("" != $proc_scrib_data(welding_maxproject))} {
	append args "-maxprojection $proc_scrib_data(welding_maxproject) "
    } else {
	append args "-maxprojection 50 "
    }
    
    eval scrib_lib_welding_spot_main $mode $proc_scrib_data(welding_file) $args

    #build topo needs to be done to build weld points into surfaces.
    ic_build_topo $V_build_topo_tol 
    ic_geo_delete_unattached
}

#
#=============== DO FEATURE STUFF ===========================
#
    set do_features ""
    set bolt_args ""
    set flange_args ""
    set fillet_args ""
    set button_args ""
    set sl_args ""

    if ![info exists V_Bolts] {set V_Bolts 0}
    if ![info exists V_number_of_nodes_on_curves]  {set V_number_of_nodes_on_curves 6}
    if {$V_Bolts == 1} {
	lappend do_features bolt
	set bolt_args [list min_hole $V_min_hole hole_4 $V_med_hole hole_6 $V_max1_hole \
	hole_8 $V_max2_hole hole_10 $V_max3_hole hole_12 $V_max4_hole max_hole $V_max_hole ]
    }

    if ![info exists V_Flanges] {set V_Flanges 0}
    if ![info exists V_notch_length] {set V_notch_length 0}
    if {$V_Flanges == 1} {
	lappend do_features flange
	set flange_args [list  flange_width $V_flange_width flange_curvature $V_flange_curvature \
	    flange_width_min $V_flange_width_min notch_length $V_notch_length ignore_tol $V_ignore_tol]
    }

    if ![info exists V_Fillets] {set V_Fillets 0}
    if {$V_Fillets == 1} {
	lappend do_features fillet
	set fillet_args [list length_min $V_Fillet_length_min length_2 $V_Fillet_length_2 \
	    length_3 $V_Fillet_length_3 length_4 $V_Fillet_length_4 length_5 $V_Fillet_length_5 \
	    ang_min $V_Fillet_ang_min ang_max $V_Fillet_ang_max]
    }

    if ![info exists V_Buttons] {set V_Buttons 0}
    if {$V_Buttons == 1} {
	lappend do_features button
	set button_args [list bead_mesh_size $V_bead_mesh_size Buttons_free $V_Buttons_free \
	    Buttons_split $V_Buttons_split Buttons_fillet $V_Buttons_fillet]
    }

    if {![info exists V_smart_loops] || ($V_smart_loops == "")} { set V_smart_loops 0}
    if {![info exists V_ring_conflict] || ($V_ring_conflict == "")} { set V_ring_conflict 1 }
    if {![info exists V_ring_conflict_distance] || ($V_ring_conflict_distance == "")} {set V_ring_conflict_distance 0}
    if {![info exists V_thin_surfs] || ($V_thin_surfs == "")} {set V_thin_surfs 0}
    if {$V_smart_loops == 1} {
	lappend do_features smart_loop
	set sl_args [list ring_conflict $V_ring_conflict conflict_distance $V_ring_conflict_distance \
	     sl_max_curvature $V_smart_loop_max_curvature sl_angle $V_smart_loop_angle \
	     sl_min_surf_area $V_smart_loop_min_surf_area sl_min_edge $V_smart_loop_min_edge \
	    mesh_size $V_mesh_size thin_surfs $V_thin_surfs sl_aspect_ratio $V_thin_surf_aspect_ratio]
    }

    scrib_lib_feature_detection $do_features $V_ratio $V_number_rings $bolt_args $flange_args \
	$fillet_args $button_args $sl_args

    foreach p [scrib_lib_geo_find_dumb_points 30 "" 0] {
	ic_geo_set_dormant_entity point $p 1
    }

#=======================================
#
#  The below is screwing up flanges...
#     scrib_lib_geo_remove_points_at_single_ends
#
#--> tetin is now ready to be meshed.
#
ic_save_tetin $meshable_geom
#
#============= MESH ====================
#
    #
    # --> if prompts is on, ask about creating mesh.
    #
    if $V_interactive { scrib_lib_exec_med_display_update }

    if {1 == $V_failure_mode} {
	if {[ tk_dialog .mesh_done "Ready to mesh" \
	      "Do you want to mesh?" "" -1 Yes No ]}  {
	    return
	}
    }
    if ![info exists V_ignore_tol ] {set V_ignore_tol 1}
    if ![info exists V_mapped_mesh ] {set V_mapped_mesh 0}
    if ![info exists V_number_rings ] {set V_number_rings 0}
    set surfs_to_mesh [ic_geo_get_objects surface $thisscript_fam]
    switch $V_mesh_method {
	quad {
	    #
	    # --> mesh with quad; return if fails
	    set failed [	ic_quad2 what surfaces entities $surfs_to_mesh element 2 proj 1 iters -20 conver 0.025 \
		geo_tol 0 ele_tol $V_ignore_tol dev 0 improvement 1 block $V_mapped_mesh \
		bunch 0 debug 0 adjust_nodes 0 adjust_nodes_max 0 try_harder 3 error_subset Failed_surfaces \
		pattern 150 big 1 board 0 remove_old -1 inner 0 simple_offset 0 enn 0 b_smooth 1 time_max 0 ele_max 0]

#geo_tol [expr $V_ignore_tol * 0.25]
#	    set failed [ic_quad_from_geometry surfaces $surfs_to_mesh 2 1 -20 0.025 \
#		[expr $V_ignore_tol * 0.25] $V_ignore_tol 0 2 $V_mapped_mesh 1 0 0 0 \
#		0.5 0.0001 3 1 -1 Failed_surfaces 170]
	}
	hexa {
	    set failed [		ic_run_mapped_based_mesher {Quad Dominant} {} $V_ignore_tol ]
	     mess "failed is $failed\n" blue
	    set new_failed ""
	    foreach f $failed {
#		set SKIPIT 1
#		foreach c [ic_geo_boundary surface $f] {
#		     if {[llength [ic_geo_incident curve $c]] > 2} continue
#		     if {[ic_geo_crv_length $c] < $V_mesh_size} continue
#		     set SKIPIT 0
#		}
#		if $SKIPIT continue
		if {[ic_geo_srf_area $f] < [expr $V_mesh_size * $V_mesh_size / 10]} continue
		set failed_f [ic_quad2 what surfaces entities $f element 2 proj 1 iters -20 conver 0.025 \
		    geo_tol 0 ele_tol $V_ignore_tol dev 0 improvement 1 block $V_mapped_mesh \
		    bunch 1 debug 0 adjust_nodes 0 adjust_nodes_max 0 try_harder 1 error_subset Failed_surfaces \
		    pattern 150 big 1 board 0 remove_old -0 inner 0 simple_offset 0 enn 0 b_smooth 0 time_max 0 ele_max 0]
		if {$failed_f > 0} {lappend new_failed $f}
	    }
	    set failed $new_failed
	     mess "valid failed surfs is $failed\n" blue
	}
    }

    if ![ic_uns_is_loaded] {mess  "valid mesh was not created\n" red ; return}
    scrib_lib_uns_unload_reload ;# necessary --jka

    #
    # --> if fewer than defined number of elements remesh at a smaller size, even if some loops failed.
    #
    set el_count [ic_uns_subset_count_elements all]
    if { $el_count < $V_num} {
	ic_unload_mesh
	#ic_delete_geometry loop all ""
	ic_set_meshing_params curve_all {} emax $V_size2
	set V_ignore_tol [expr $V_ignore_tol * $V_ignore_tol / $V_mesh_size]
	ic_save_tetin $meshable_geom
	mess "only $el_count elements in mesh. \
	    Need to re-mesh at size $V_size2\n" blue
	switch $V_mesh_method {
	    quad {
	    set failed [	ic_quad2 what surfaces entities $surfs_to_mesh element 2 proj 1 iters -20 conver 0.025 \
		geo_tol 0 ele_tol $V_ignore_tol dev 0 improvement 1 block $V_mapped_mesh \
		bunch 0 debug 0 adjust_nodes 0 adjust_nodes_max 0 try_harder 3 error_subset Failed_surfaces \
		pattern 150 big 1 board 0 remove_old -1 inner 0 simple_offset 0 enn 0 b_smooth 1 time_max 0 ele_max 0]

#		set failed [ic_quad_from_geometry surfaces $surfs_to_mesh 2 1 20 0.025 \
#		    [expr $V_ignore_tol * 0.25] $V_ignore_tol 0 2 $V_mapped_mesh 1 0 0 0 0.5 0.0001 3 1 -1 Failed_surfaces 150]
	    }

	    hexa {
		set failed [		ic_run_mapped_based_mesher {Quad Dominant} $surfs_to_mesh $V_ignore_tol ]
		mess "failed is $failed\n" blue
		set new_failed ""
		foreach f $failed {
#		    set SKIPIT 1
#		    foreach c [ic_geo_boundary surface $f] {
#			if {[llength [ic_geo_incident curve $c]] > 2} continue
#			if {[ic_geo_crv_length $c] < $V_mesh_size} continue
#			set SKIPIT 0
#		    }
#		    if $SKIPIT continue
		    if {[ic_geo_srf_area $f] < [expr $V_mesh_size * $V_mesh_size / 10]} continue
		    set failed_f [ic_quad2 what surfaces entities $f element 2 proj 1 iters -20 conver 0.025 \
			geo_tol 0 ele_tol $V_ignore_tol dev 0 improvement 1 block $V_mapped_mesh \
			bunch 1 debug 0 adjust_nodes 0 adjust_nodes_max 0 try_harder 1 error_subset Failed_surfaces \
			pattern 150 big 1 board 0 remove_old -0 inner 0 simple_offset 0 enn 0 b_smooth 0 time_max 0 ele_max 0]
		    if {$failed_f > 0} {lappend new_failed $f}
		}
		set failed $new_failed
		mess "valid failed surfs is $failed\n" blue
	    }
	}
    }

    if $V_interactive {scrib_lib_exec_med_display_update} 
    if {$failed > 0} {
	mess "\n\n======================================\n"
	mess "failure is $failed \n"
	mess "Could not mesh model properly, returning.\n"
	mess "======================================\n"
	return
    }
if {1 == $V_failure_mode} {
    
    mess "Performing safe mode operations...\n\n" red
    #
    # save nastran file as a backup, in case clean fails
    #
    ic_save_unstruct $interim_mesh 1 {} {} {} {} 0
    
    if [ic_uns_check_family RINGS] { ic_geo_new_family RINGS }
    
    scrib_lib_output_thickness_set_nastran $thisscript_fam \
	$V_naspid $V_thickness $out_boco 1
    
    scrib_lib_output_nastran $interim_mesh $out_boco $export_file $V_nasform
    
    mess "\n...finished safe mode operations\n\n" red
} 
#
# --> clean up and check quality
#

##Jason,  I get different results with mesh quality in interactive vs. batch because of the line below???
if $V_interactive { scrib_lib_exec_med_display_update }
scrib_lib_quality_surface_mesh_custom_standard 

if !$V_editmesh {
	set num_elements [scrib_lib_quality_check]
	ic_uns_renumber_all_nodes 1 1
	ic_uns_renumber_all_elements 1 1
	ic_save_unstruct $interim_mesh
	scrib_lib_output_thickness_set_nastran $thisscript_fam $V_naspid	$V_thickness $out_boco 1
	scrib_lib_output_nastran $interim_mesh $out_boco $export_file $V_nasform

	if {[info exists badnaspid] && $badnaspid} {
	    mess "\n\n***Part $V_model is returning pid of $badnaspid.\
		    This may be a problem!\nPlease verify that this is correct\n" red
	}

	set root_name [file root $interim_mesh]
	set xml_title [file tail $$interim_mesh] 
	set script "mesh_quad.tcl"
	ic_reports_write_mesh_report All ${root_name}.xml -format xml -mesher "Batch Surface" \
	    -title "$xml_title" -script "$script"
	if $V_interactive {ic_view home}
}
if {1 == $V_failure_mode} {
    if {[ tk_dialog .mesh_done "Meshing is done" \
	      "Do you want to clean the mesh?" "" -1 Yes No ]}  {
	return
    }
}

set types ""
foreach type {QUAD_4 TRI_3} {
    if {[lsearch [ic_uns_subset_list_types all] $type] != -1} { lappend types $type }
}
if {0 >= [ic_count_nodes]} {
    mess "Error: mesh has no nodes...returning from quad cleaning process\n" red
    return 1
}

# --> D E L E T E   A L L   D U P L I C A T E, DISCONNECTED, ETC   E L E M E N T S

scrib_lib_quality_duplicate_elements_delete
scrib_lib_quality_disconnected_bars_delete    
scrib_lib_quality_hanging_bars_delete    
ic_delete_disconnected_vertices


# ----> C H E C K   A N D   F I X   O V E R L A P S

#This might be having problems...
#scrib_lib_quad_remesh_by_diagnostic overlap $thisscript_fam {TRI_3 QUAD_4} 2
#
# ----> TRI to QUAD
#

ic_change_tri_quad_2 all 1 0 0 0 160 20 0

#
# ----> R E M O V E   B A R S   A T   G I V E N   F E A T U R E   A N G L E
#

if {[info exists V_ignore_angle] && (0 < $V_ignore_angle)} {
    #
    # we want to exclude the SHADOW family (scrib_lib_welding_shadow_family_name) from the list
    #
    set remove_fams [ic_uns_list_families]
    set shadow_fam [scrib_lib_welding_shadow_family_name $V_naspid]
    if {"" != $shadow_fam} {
	set ind [lsearch $remove_fams $shadow_fam]
	if {0 <= $ind} {
	    # first we have to move the point elements from thisscript_fam to shadow_fam
	    set s [ic_uns_subset_create]
	    ic_uns_subset_add_families_and_types $s $thisscript_fam NODE
	    ic_uns_change_family $s $shadow_fam
	    ic_uns_subset_delete $s
	    set remove_fams [lreplace $remove_fams $ind $ind]
	}
    }
    scrib_lib_quad_remove_bars_by_feature_angle $remove_fams {NODE BAR_2 TRI_3 QUAD_4} $V_ignore_angle
}

#
# ----> TRY TO IMPROVE MESH BY MESH EDITING ---------
#

#merge nodes.  May not be useful...
#if ![info exists V_mergetolerance] {set V_mergetolerance 0}
#if $V_mergetolerance {ic_uns_merge_nodes all $V_mergetolerance [list 0 0 0] [list 0 0 0] 0 1}

ic_smooth_elements upto 1 metric Quality iterations 5 laplace 1 smooth TRI_3 smooth QUAD_4 all_elements 0
ic_smooth_elements upto 1 metric Quality iterations 5 laplace 0 smooth TRI_3 smooth QUAD_4 all_elements 0

    #scrib_lib_quality_surface_mesh_custom_standard

    foreach upto $V_SmoothingUptos {
#	if {$upto < 0.7} {ic_uns_merge_nodes all 7.5 {0 0 0} {0 0 0} 0 1 1}
	catch {
	    ic_smooth_elements map {} upto $upto iterations 5 fix_families {} smooth TRI_3 smooth QUAD_4 \
		violate_geometry $V_ViolateGeomVal min_edge_len $V_Q_ME_Q4_min all_elements 1 metric "Custom Quality"
	} res
    }


#It would be nice to remesh bad elements, but I think this doesn't work with immutable elements.

if $V_interactive { scrib_lib_exec_med_display_update }

if {1 == $V_failure_mode} {
    if {[ tk_dialog .pattern_done "Continue cleaning?" \
	      "Do you want to continue?" "" -1 Yes No ]}  {
	return
    }
}


# ----> SMOOTH AND REMESH TO GET GOOD QUALITY MESH 
if 0 {
mess "Smoothing the mesh...\n\n"

foreach val {0.1 0.5 1.0} {
    
    # ----> S M O O T H   A L L   T R I S   A N D   Q U A D S
    
    scrib_lib_quad_smooth_by_quality $thisscript_fam \
	$types {Quality} $val [concat all_elements 1 $smooth_args]
    
    scrib_lib_quad_smooth_by_quality $thisscript_fam \
	$types {Quality} 1.0 [concat laplace 1 $smooth_args]
    
    scrib_lib_quality_surface_mesh_custom_standard 

    scrib_lib_quad_smooth_by_quality $thisscript_fam \
	$types {Custom quality} 1.0  $smooth_args
    
    #	scrib_lib_quad_clean_debug_save
    
#    scrib_lib_quad_remesh_bad_elements $thisscript_fam \
#	$types {Custom quality} 1.0 2 0 $ring_fam
    
    #	 scrib_lib_quad_clean_debug_save
    
    if {1 == $V_failure_mode} {
	if {[ tk_dialog .pattern_done "Continue cleaning?" \
		  "Do you want to continue?" "" -1 Yes No ]}  {
	    return
	}
    }
}

# -->

if $V_mergetolerance {ic_uns_merge_nodes all $V_mergetolerance [list 0 0 0] [list 0 0 0] 0 1}

mess "Smoothing by custom quality...\n\n"

scrib_lib_quad_smooth_by_quality $thisscript_fam \
    $types {Custom quality} 1.0 [concat laplace 1 $smooth_args]

scrib_lib_quad_remesh_bad_elements $thisscript_fam \
    $types {Custom quality} 1.0 2 0 $ring_fam

# ----> IF WE STILL HAVE BAD MESH, AND USER CAN ALLOW IGNORING DIM, REMESH WITH IGNORE DIM

if {![info exists V_IgnoreDim] || ($V_IgnoreDim == "")} { set V_IgnoreDim 0 }

if $V_IgnoreDim {
    
    mess "Remeshing bad elements while ignoring dimension...\n\n"

    set stat [scrib_lib_quad_remesh_bad_elements $thisscript_fam \
		  $types {Custom quality} $V_IgnoreDimUpto 2 1 $ring_fam]
    scrib_lib_quad_clean_debug_save
}
}

# ----> A G A I N   D E L E T E { disconnected bars, hanging bar elements, disconnected vertices }

scrib_lib_quality_disconnected_bars_delete    
scrib_lib_quality_hanging_bars_delete    
ic_delete_disconnected_vertices

#
# ---> SET THE THICKNESS, and SAVE THE NASTRAN MESH
#
set num_elements [scrib_lib_quality_check]
ic_uns_renumber_all_nodes 1 1
ic_uns_renumber_all_elements 1 1
ic_save_unstruct $interim_mesh
scrib_lib_output_thickness_set_nastran $thisscript_fam $V_naspid	$V_thickness $out_boco 1
scrib_lib_output_nastran $interim_mesh $out_boco $export_file $V_nasform

if {[info exists badnaspid] && $badnaspid} {
    mess "\n\n***Part $V_model is returning pid of $badnaspid.\
	    This may be a problem!\nPlease verify that this is correct\n" red
}

set root_name [file root $interim_mesh]
set xml_title [file tail $$interim_mesh] 
set script "mesh_quad.tcl"
ic_reports_write_mesh_report All ${root_name}.xml -format xml -mesher "Batch Surface" \
    -title "$xml_title" -script "$script"
if $V_interactive {ic_view home}
set y [expr [clock seconds] - $x]
mess "Time to mesh $V_model is $y seconds\n"














































