
# Stuff to run the mesher.  This does not include any of the code that
# handles the mesh after it has been loaded, or the mesher form.
#
# Copyright (c) 1993, 1994 Pacific Marketing and Consulting
# Author:  Wayne A. Christopher, wayne@pmac.com
#          Pacific Marketing and Consulting, Berkeley, California
#

proc grid_set_type_tetra {} {
    global grid_type grid_qual
    
    set grid_type tetra
    set grid_qual aspect
    return 0
}

proc edit_grid_tetra {d} {
    global prism_path tetssi_path unit_default prisms_on_all_families
    global app_name
    
    #grid_edit_unit_form $d.units {1 0 -cols -}
        
    form_checkbutton $d.uset "Max tetra size" grid_usesize_x {0 0}
    form_entry $d.x grid_size_x float {0 1} grid_usesize_x
    
    form_checkbutton $d.sm "Smooth mesh" grid_tetra_sm {2 0}
    form_label $d.smquall "Up to quality" {2 1}
    form_label $d.smitersl "Iterations" {3 1}
    form_entry $d.smqual grid_tetra_smqual float {2 2} grid_tetra_sm
    form_entry $d.smiters grid_tetra_smiters float {3 2} grid_tetra_sm
    form_checkbutton $d.coa "Coarsen mesh" grid_tetra_smcoarse \
	{5 0} grid_tetra_sm
    form_label $d.coaspl "Min aspect" {5 1} \
	{grid_tetra_sm grid_tetra_smcoarse}
    form_label $d.coitersl "Iterations" {6 1} \
	{grid_tetra_sm grid_tetra_smcoarse}
    form_entry $d.coasp grid_tetra_smcasp float {5 2} \
	{grid_tetra_sm grid_tetra_smcoarse}
    form_entry $d.coiters grid_tetra_smciters int {6 2} \
	{grid_tetra_sm grid_tetra_smcoarse}
    
    if {$app_name == "autohex_generic"} {
	form_checkbutton $d.csurf "Only surface mesh" \
	    grid_tetra_surface {8 0}
	form_checkbutton $d.tquad "Convert to quads" \
	    grid_tetra_to_quad {8 1 -cols 2} grid_tetra_surface
    }
    
    if {$prism_path != "not_found"} {
	form_checkbutton $d.pr "Create prisms" grid_tetra_prisms {17 0}
	set g1 {17 1 -cols 2}
	if ![info exists prisms_on_all_families] {
	    form_button $d.fams "Families" grid_tetra_prism_families {17 1} \
		grid_tetra_prisms
	    set g1 {17 2}
	}
	form_button $d.pedit "Parameters" edit_grid_tetra_pparams $g1 \
	    grid_tetra_prisms
    }
    
    form_checkbutton $d.po "Per-object params" grid_perobject {20 0}
    form_button $d.epo " Edit " grid_edit_perobject_params \
	{20 1} grid_perobject
    
    form_checkbutton $d.mps "Mesh assemblies separately" \
	grid_mesh_parts_separate {21 0 -cols -}
    form_checkbutton $d.difft "Allow different subgrid types" \
	grid_different_subgrid {22 0 -cols -} grid_mesh_parts_separate
    
    set gs [form_label_frame $d.pp "Global settings" {30 0 -cols -}]
    
    form_label $gs.settingsl "Mesh parameters" {0 0}
    futil_menuentry_labels $gs.settings grid_tetra_settings_type \
	{list {normal Normal} {coarse Coarse}} {0 1} "" \
	{grid_set_tetra_defaults $grid_tetra_settings_type 1} 6
    
    form_label $gs.ratl "Expansion ratio" {1 0}
    form_label $gs.cgapl "Cells in gap" {2 0}
    form_label $gs.defcl "Default max curve size" {7 0}
    form_label $gs.defsl "Default max surface size" {8 0}
    
    form_entry $gs.rat grid_tetra_params(tetra_ratio) float {1 1}
    form_entry $gs.cgap grid_tetra_params(n_cells_in_gap) int {2 1}
    form_entry $gs.defc grid_tetra_params(tetra_size_on_curves) float {7 1}
    form_entry $gs.defs grid_tetra_params(tetra_size_on_surfs) float {8 1}
    
    form_button $gs.tpar "Advanced parameters" edit_grid_tetra_tparams \
	{20 0 -cols 2}
}

proc edit_grid_tetra_pparams {} {
    global grid_tetra_prism_height
    
    set d [form_init .grid_tetra_pparams "Prism params" {mesh sub}]
    if {$d != ""} {
	if {[info commands app_set_prism_params] != ""} {
	    form_button $d.defs "Set using Y+" app_set_prism_params {0 0}
	    form_entry $d.ypls grid_tetra_prism_yplus float {0 1}
	}
	form_label $d.prnl "Num layers" {8 0}
	form_label $d.prhl "Init height" {9 0}
	form_label $d.prrl "Height ratio" {10 0}
	form_label $d.prsl "Smoothing steps" {11 0}
	form_entry $d.prn grid_tetra_prism_num int {8 1}
	form_entry $d.prh grid_tetra_prism_height float {9 1}
	form_entry $d.prr grid_tetra_prism_ratio float {10 1}
	form_entry $d.prs grid_tetra_prism_sms int {11 1}
	form_finish bot
    }
}

proc edit_grid_tetra_tparams {} {
    global tetssi_path ssish_path
    
    set d [form_init .grid_tetra_tparams "Tetra params" {mesh sub}]
    if {$d != ""} {
	
	form_label $d.ttoll "Triangulation tolerance" {1 0}
	form_label $d.edgecl "Edge criterion" {3 0}
	form_label $d.natsfl "Natural size factor" {4 0}
	form_label $d.natrefl "Natural size refinement" {5 0}
	form_label $d.triesl "Volume assignment passes" {6 0}
	
	form_entry $d.ttol grid_triangulation_tolerance float {1 1}
	form_entry $d.edgec grid_tetra_params(edge_criterion) float {3 1}
	form_entry $d.natsf grid_tetra_params(natural_size_factor) float {4 1}
	form_entry $d.natref grid_tetra_params(natural_size_refinement) int {5 1}
	form_entry $d.tries grid_cutter_tries int {6 1}
	
	form_checkbutton $d.splitspan "Split spanning edges" \
	    grid_tetra_params(split_spanning) {9 0 -cols 2}
	
	if {($tetssi_path != "not_found") || ($ssish_path != "not_found")} {
	    form_checkbutton $d.ssi "Add intersection curves" grid_run_tetssi \
		{10 0 -cols 2}
	}
	form_checkbutton $d.addfaces "Automatic hole repair" \
	    grid_allow_addfaces {11 0 -cols 2}
	form_checkbutton $d.notet "Re-use tetra output" \
	    grid_no_tetra {12 0 -cols 2}
	form_checkbutton $d.nocut "Re-use cutter output" \
	    grid_no_cutter {13 0 -cols 2}
	
	form_checkbutton $d.csurf "Save surface from cutter" \
	    grid_cutter_surface {14 0 -cols 2}
	
	form_checkbutton $d.oldstyle "Use old-style multi-pass mesher" \
	    grid_tetra_oldstyle {15 0 -cols 2}
	
	form_finish bot
    }
}

proc grid_tetra_prism_families {} {
    global grid_prism_families
    
    set opts ""
    foreach f [tetin_prism_family_list 1] {
	lappend opts $f
	if ![info exists grid_prism_families($f)] {
	    set grid_prism_families($f) 0
	}
    }
    check_box_form .tetra_prism_families "Prism families" $opts 6 \
	grid_prism_families
}

proc grid_runonce_tetra {gfile mfile efile pfile mapfile do_part suff inc_others} {
    global advanced_mesher_ok grid_current_prefix tetra_path app_name
    global grid_tetra_surface no_run_mesher 
    global grid_tetra_sm grid_tetra_smcoarse
    global grid_tetra_smqual grid_tetra_smiters
    global grid_tetra_smcasp grid_tetra_smciters
    global no_exit_job
    
    set tetin tetin_auto$suff
    set domain grid_output$suff
    
    if !$advanced_mesher_ok {
	mess "Warning: you do not have a license for the Tetra mesher. \
		Please contact technical support.\n" red
    }
    
    set grid_current_prefix ""
    
    if ![file executable $tetra_path] {
	mess "Error: the tetra binary could not be found!\n" red
	mess "Path = $tetra_path\n"
	return 0
    }
    
    set usefam 0
    if {($app_name == "autohex_generic") && $grid_tetra_surface} {
	# In this special case we use the given int_fam names for the
	# volume - they will get thrown away anyhow.
	set usefam 2
    }
    
    mess "Writing [directory]/$tetin ...\n"
    write_tetin_file [directory]/$tetin $usefam "" 1 1 $do_part $inc_others $suff 1
    mess "Done.\n"
    
    grid_write_mapping $mapfile $suff
    
    cmd_rm $mfile
    if [file exists $mfile] {
	user_error "Can't remove the file $mfile before running mesher --\
               please check the permissions on the directory [directory mesh]"
	return
    }
    
    if [info exists no_run_mesher] {
	mess "Not running mesher\n" red
	return 0
    }
    
    set tetra_in [directory]/tetra_in$suff
    
    # This is the all-in-one version
    set fp [open $tetra_in w]
    
    puts $fp "SurfaceFile      \"$tetin\""
    puts $fp "DomainOutputFile \"$domain\""
    
    puts $fp "auto_inter       1"
    
    puts $fp "run_cutter       1"
    puts $fp "auto_vol         1"
    
    puts $fp "run_smoother     $grid_tetra_sm"
    puts $fp "smoother_aspect  $grid_tetra_smqual"
    puts $fp "smoother_n_iter  $grid_tetra_smiters"
    
    puts $fp "run_coarsener    [expr $grid_tetra_smcoarse && $grid_tetra_sm]"
    puts $fp "coarsen_aspect   $grid_tetra_smcasp"
    puts $fp "n_coarsen_iter   $grid_tetra_smciters"
    
    puts $fp "fix_non_manifold 1"
    
    close $fp
    
    mess "Running mesher...\n"
    set no_exit_job mesher
    
    set cmd1 [list $tetra_path tetra_in$suff -nproc 1]
    set cut [directory]/$domain
    
    set ignore_messages [list "*faces in _*" \
			     "*element(s) contain material*" \
			     "*elements marked in *" \
			     "*element(s) are in family*" \
			     "*splitting * into * and*"]
    
    cmd_rm $cut
    run_background $cmd1 [directory] 3 "" $ignore_messages
    if ![file exists $cut] {
	unset no_exit_job
	return 0
    }
            
    tetin_free_cutouts_for_solid
    
    unset no_exit_job
    return 1
}

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

proc grid_any_tetra_params_used {sh} {
    foreach i {height} {
	foreach v [$sh get -grid_${i}] {
	    if $v { return USED }
	}
    }
    return ""
}

proc grid_set_all_tetra_enabled {on} {
    global edit_params_active
    foreach i [array names edit_params_active] {
	set edit_params_active($i) $on
    }
}

proc grid_edit_tetra_perobject {} {
    global edit_params_active edit_params_used
    global object_type_list object_type_title form_done_flag botform_geo
    global grid_perobject_buttons
    
    set buts [list done cancel \
		  [list "Enable all" "grid_set_all_enabled 1"] \
		  [list "Disable all" "grid_set_all_enabled 0"]]
    
    catch {unset edit_params_active}
    catch {unset edit_params_used}
    catch {unset grid_perobject_buttons}
    
    form_kill .grid_tetra_perobject
    set d [form_init .grid_tetra_perobject "Per-object tetra sizes" \
	       "mesh sub" $buts]
    if {$d == ""} return
    
    set fr [form_scroller $d.scr 400 {0 0}]
    
    set row 1
    foreach type $object_type_list {
	switch $type { material - part continue }
	
	set objects ""
	foreach obj [db_list_objects $type] {
	    if [$obj si_value active] { lappend objects $obj }
	}
	if {$objects == ""} continue
	
	form_label $fr.l$row "$object_type_title($type):" \
	    "$row 0 -cols -"
	incr row
	
	foreach obj $objects {
	    if {$type == "domain"} {
		set obname ""
	    } else {
		set obname [$obj getval name]
	    }
	    set sects [$obj getval section_list]
	    switch [llength $sects] {
		0 continue
		1 {
		    set sh [$obj getval ${sects}_shape]
		    if {[$sh get -shtype] == "none"} continue
		    set edit_params_active($sh) [$sh get -grid_enabled]
		    set edit_params_used($sh) [grid_any_params_used $sh]
		    form_checkbutton $fr.a$row $obname \
			edit_params_active($sh) "$row 3"
		    set grid_perobject_buttons($sh) $fr.a$row
		    form_button $fr.b$row Edit "grid_tetra_perobject_one $obj $sh" \
			"$row 4" edit_params_active($sh)
		    form_label $fr.u$row "" "$row 5" edit_params_active($sh)
		    $fr.u$row configure -textvariable edit_params_used($sh)
		    incr row
		}
		default {
		    form_label $fr.l$row $obname "$row 1 -cols 2"
		    incr row
		    foreach ss $sects {
			set sh [$obj getval ${ss}_shape]
			if {[$sh get -shtype] == "none"} continue
			set edit_params_active($sh) [$sh get -grid_enabled]
			set edit_params_used($sh) [grid_any_params_used $sh]
			form_checkbutton $fr.a$row $ss \
			    edit_params_active($sh) "$row 3"
			set grid_perobject_buttons($sh) $fr.a$row
			form_button $fr.b$row Edit "grid_tetra_perobject_one $obj $sh" \
			    "$row 4" edit_params_active($sh)
			form_label $fr.u$row "" "$row 5" \
			    edit_params_active($sh)
			$fr.u$row configure -textvariable edit_params_used($sh)
			incr row
		    }
		}
	    }
	}
    }
    form_colwidth $fr 0 2 M
    form_colwidth $fr 1 2 M
    
    grid_tetra_sizes_out
    
    form_finish bot
    $d.scr configure -height [expr {[winfo reqheight $d.scr] + 1}]
    
    if ![form_wait .grid_tetra_perobject] return
    
    grid_tetra_sizes_in
    
    foreach sh [array names edit_params_active] {
	$sh configure -grid_enabled $edit_params_active($sh)
    }
}

proc grid_tetra_perobject_type {sh} {
    global domain edit_tetra_params_for use_grid_grading
    
    set obj [$sh get -object]
    
    set tt [lindex [split [$sh get -type] _] 1]
    set tp $tt
    switch $tt {
	quad    { append tt _[$sh getval plane] }
	incline {
	    append tt _[$sh getval axis]
	    if {[$sh si_value thickness] != 0} {
		append tt _thick
	    }
	}
	polygon {
	    set hgt [$sh si_value height]
	    if !$hgt {
		set tt polygon_thin
		
	    } else {
		set n [$sh getval nverts]
		append tt _$n
		if ![info exists edit_tetra_params_for($tt)] {
		    set hh ""
		    for {set i 0} {$i < $n} {incr i}  {
			set i2 [expr {$i + 2}]
			lappend hh [list "Side [expr $i + 1] size" height $i2]
		    }
		    set edit_tetra_params_for($tt) \
			[concat [list [list "Bottom height" height 0] \
				     [list "Top height" height 1]] $hh]
		}
	    }
	}
    }
    if {$obj == $domain} { append tt _domain }
    return $tt
}

proc grid_tetra_perobject_one {obj sh} {
    global edit_params_used edit_params_for form_done_flag botform_geo
    global edit_param_val edit_param_on domain meshing_units
    global grid_copyto_mode use_grid_grading edit_tetra_params_for
    
    set tt [grid_tetra_perobject_type $sh]
    
    set tw .grid_tetra_params_$tt
    
    set buts [list done cancel [list "Copy to" "grid_perobject_copyto $tt"]]
    set d [form_init $tw "" "grid sub sub" $buts]
    top_title $tw [$obj getval name]
    
    set u $meshing_units
    
    if {$d != ""} {
	form_label $d.top1 Requested {0 1}
	# form_label $d.top2 Actual {0 2}
	set sc [form_scroller $d.fr 500 {1 0 -cols -}]
    }
    set r 1
    if [info exists edit_tetra_params_for($tt)] {
	set params $edit_tetra_params_for($tt)
    } else {
	set params $edit_params_for($tt)
    }
    foreach p $params {
	if {$p == ""} {
	    incr r
	    continue
	}
	set ptype [lindex $p 1]
	if {$ptype == "height"} {
	    if {$d != ""} {
		form_checkbutton $sc.l$r [lindex $p 0] edit_param_on($tt,$r) "$r 0"
		form_entry $sc.e$r edit_param_val($tt,$r) float "$r 1" \
		    edit_param_on($tt,$r)
	    }
	}
	set n [lindex $p 2]
	set rval [lindex [$sh get -grid_$ptype] $n]
	set aval [lindex [$sh get -grid_${ptype}_used] $n]
	if {($rval == "") || ($rval == 0)} {
	    set edit_param_on($tt,$r) 0
	    switch $ptype {
		height { set edit_param_val($tt,$r) 0 }
		length { set edit_param_val($tt,$r) 0 }
		ratio  { set edit_param_val($tt,$r) 2 }
	    }
	} else {
	    set edit_param_on($tt,$r) 1
	    if {$ptype == "height"} {
		set edit_param_val($tt,$r) [unit_convert $rval $u 1]
	    } else {
		set edit_param_val($tt,$r) $rval
	    }
	}
	
	incr r
    }
    if {$d != ""} {
	form_finish bot
	$d.fr configure -height [expr {[winfo reqheight $d.fr] + 1}]
    }
    
    tkwait variable form_done_flag($tw)
    if !$form_done_flag($tw) return
    
    grid_perobject_toshape $sh $tt 0
    if [info exists grid_copyto_mode] {
	grid_perobject_copyto $tt
    }
}

proc grid_tetra_params {sh} {
    global edit_params_for
    
    set tt [grid_perobject_type $sh]
    set stuff ""
    foreach p $edit_params_for($tt) {
	if {([lindex $p 1] != "height") || ([lindex $p 3] != "")} continue
	lappend stuff [list [lindex $p 0] [lindex $p 2]]
    }
    return $stuff
}

proc grid_tetra_sizes_out {} {
    global edit_params_tetsize meshing_units
    
    set u $meshing_units
    
    foreach shi [array names edit_params_tetsize] {
	set val [lindex [[lindex $shi 0] get -grid_height] [lindex $shi 1]]
	if {($val == "") && ($val == 0)} {
	    set edit_params_tetsize($shi) ""
	} else {
	    set edit_params_tetsize($shi) [unit_convert $val $u 1]
	}
    }
}

proc grid_tetra_sizes_in {} {
    global edit_params_tetsize meshing_units
    
    set u $meshing_units
    
    foreach shi [array names edit_params_tetsize] {
	set sh [lindex $shi 0]; set n [lindex $shi 1]
	set nv [unit_convert $edit_params_tetsize($shi) $u 0]
	if {$nv == ""} { set nv 0 }
	set val [$sh get -grid_height]
	set vl [llength $val]
	while {$vl <= $n} { lappend val 0; incr vl }
	set val [lreplace $val $n $n $nv]
	$sh configure -grid_height $val
    }
}
