#!/bin/sh ################################################################################ # TempoTk - a graphical interface to the TEMPO pulsar timing package. \ exec impulse "$0" "$@" ################################################################################ # # Synopsis: TempoTk is greatly speeds up the "lk+vi" approach to using TEMPO # by organizing TOAs, parfiles and residuals all on a single screen # as well as using some useful keybindings to do various tasks. # # Author: Duncan Lorimer (drl@jb.man.ac.uk) # # Language: Tcl/Tk (this file) but requires the "impulse" extension to Tcl/Tk # to be installed first. See http://www.jb.man.ac.uk/~drl/impulse # # Usage: type "tempotk" for instructions on firing up the gui! # # History: # # October 2001: original version created during a Parkes observing run # April 2005: after some interim mods, code now overhauled for general release # ################################################################################ proc deleteline {widget line} { global tempo set tempo(deleted) [$widget get $line.0 $line.end] $widget delete $line.0 [expr $line+1].0 } ################################################################################ proc pasteline {widget line} { global tempo if {$tempo(deleted) == ""} {return} puttextline $widget $line $tempo(deleted)\n } ################################################################################ proc getselected {widget first last} { upvar first f last l set f [set l 0] catch {scan [$widget index sel.first] %d.%d f c} catch {scan [$widget index sel.last ] %d.%d l c} } ################################################################################ proc gettextline {widget} { scan [$widget index insert] %d.%d line column return [$widget get $line.0 $line.end] } ################################################################################ proc zaptextline {widget line} { $widget delete $line.0 $line.end } ################################################################################ proc puttextline {widget line text} { $widget insert $line.0 $text } ################################################################################ proc textlinenum {widget} { scan [$widget index insert] %d.%d line column return $line } ################################################################################ proc commentline {widget line} { set text [$widget get $line.0 $line.end] zaptextline $widget $line switch [lindex $text 0] { C { set text [string range $text 2 end] set result 0 } default { set text "C $text" set result 1 } } puttextline $widget $line $text return $result } ################################################################################ proc savetempo {} { global tempo set file [open $tempo(timfile) w] if {$tempo(MODE)} {puts $file "MODE $tempo(MODE)"} puts $file "EFAC $tempo(EFAC)" puts $file [.tempo.input.timfile.txt get 1.0 end] close $file set skip 0 set tempo(TOAS) "" set file [open $tempo(timfile) r] while {[readline $file line]} { if {$line == "SKIP"} {set skip 1} if {$line == "NOSKIP"} {set skip 0} if {[expr [llength $line] > 3] && [lindex $line 0] != "C"} { if {!$skip} {lappend tempo(TOAS) $line} } } close $file set file [open $tempo(parfile) w] puts $file [.tempo.input.parfile.txt get 1.0 end] puts $file "NITS $tempo(NITS)" close $file } ################################################################################ proc ideal_chisqr {} { global tempo set tempo(EFAC) 1.0 set tempo(MODE) 1 tempo noplot if ![catch {set idealefac [expr sqrt($tempo(Chisqr/nfree))]}] { if [expr abs(1.0-$tempo(Chisqr/nfree)) > 0.1] { set tempo(EFAC) [format %.2f $idealefac] } } tempo show_message \ "EFAC has been adjusted so that Chisqr/nfree should now be of order unity" } ################################################################################ ## help on setepoch ## setepoch - set epoch of period in the current ephemeris to a given MJD ## ## usage: setepoch $mjd ## ## setepoch asks TEMPO to write out the pulse turns to a temporary file ## before it changes the PEPOCH in the current ephemeris file and calls ## tempo again reading in the same set of pulse turns. The final ephemeris ## returned by tempo is then copied over the old one. ## ## Last update: Oct 19 2001 ## help end ################################################################################ proc setepoch {epoch} { global tempo catch "exec tempo -f $tempo(parfile) $tempo(timfile) -no turns" exec cp $tempo(PSR).par $tempo(parfile) exec echo "PEPOCH $epoch" >> $tempo(parfile) catch "exec tempo -f $tempo(parfile) $tempo(timfile) -ni turns" exec cp $tempo(PSR).par $tempo(parfile) exec rm -f turns loadpar tempo show_message "The epoch of period in the ephemeris has now been set to MJD: $epoch" set tempo(EPOCH) $epoch } ################################################################################ proc tempo {args} { global tempo pgplot catch {selection clear} savetempo if [catch {set output [exec tempo -f $tempo(parfile) $tempo(timfile)]}] { error "error running tempo!" } set file [open $tempo(PSR).par] while {[readline $file line]} { set key [lindex $line 0] if {$key != ""} { set tempo($key) [lindex $line 1] } } close $file set tempo(output) $output set file [open tempo.out w] puts $file $tempo(output) close $file set tempo(unit) s set tempo(rmsvalue) [resid2 rms] if [expr $tempo(rmsvalue) < 0.5e-3] { set tempo(unit) \\gms set tempo(rmsvalue) [expr $tempo(rmsvalue)*1.0e6] } elseif [expr $tempo(rmsvalue) < 0.5] { set tempo(unit) ms set tempo(rmsvalue) [expr $tempo(rmsvalue)*1.0e3] } set tempo(rmsvalue) [format %.1f $tempo(rmsvalue)] if {$tempo(MODE)} { set idx [expr [lsearch $tempo(output) Chisqr/nfree:]+4] set tempo(Chisqr/nfree) [lindex $tempo(output) $idx] } if {$args != "noplot"} { pgslct $pgplot($tempo(resplot)) plotresiduals # pgslct 2 # plothistogram # pgslct $pgplot($tempo(resplot)) } set file [open tempo.out] readline $file line wm title .tempo $line close $file .tempo.output.lis delete 0 end set file [open tempo.lis] while {[readline $file line]} {.tempo.output.lis insert end $line} close $file .tempo.output.lis yview end } ############################################################################### proc getdistance {} { global tempo eqgal $tempo(RAJ) $tempo(DECJ) l b puts [dmd $l $b $tempo(DM)] } ############################################################################### proc plothistogram {args} { global ydata nbin ymin ymax adv set nbin 15 hist $ydata $ymin $ymax } ############################################################################### proc plotresiduals {args} { global tempo xdata ydata xmin xmax ymin ymax erydat erycol pgbegin pgbbuf adv cd [exec pwd] # save TOA erros as a global for identification in cursor mode set tempo(etoa) "" foreach etoa [resid2 etoa] { lappend tempo(etoa) [format %.2f $etoa] } # get the appropriate pre/postfit residual and unit switch $tempo(resid) { Pre-fit { switch $tempo(unit) { s { set ydata [resid2 presec] set erydat [resid2 etoas] } ms { set ydata [resid2 prems] set erydat [resid2 etoams] } \\gms { set ydata [resid2 preus] set erydat [resid2 etoa] } } } Post-fit { switch $tempo(unit) { s { set ydata [resid2 pfsec] set erydat [resid2 etoas] } ms { set ydata [resid2 pfms] set erydat [resid2 etoams] } \\gms { set ydata [resid2 pfus] set erydat [resid2 etoa] } default { puts help } } } } range $ydata ymin ymax set ymin [expr -1.0*[set ymax [expr 1.5*[max [expr abs($ymin)] $ymax]]]] set xdata "" switch $tempo(xscale) { days { set mjd0 [expr int([lindex [set mjd [resid2 mjd]] 0])] foreach date $mjd { lappend xdata [expr $date-$mjd0] } xlabel "Days after MJD $mjd0.0" } mjd { set xdata [resid2 mjd] xlabel MJD } date { foreach mjd [resid2 mjd] {lappend xdata [year $mjd]} xlabel Date } doy { foreach mjd [resid2 mjd] { set year [year $mjd] lappend xdata [expr 365.25*($year-int($year))] } xlabel "Day of year" } index { set xdata [numerate $ydata] xlabel "TOA index" } orphi { set xdata [resid2 orphi] xlabel "Orbital Phase" } } # autoscale xlimits if necessary if {$args != "customlimits"} { range $xdata xmin xmax set delx [expr 0.1*[expr $xmax-$xmin]] set xmin [expr $xmin-$delx] set xmax [expr $xmax+$delx] if {$tempo(xscale) == "orphi"} { set xmin -0.05 set xmax 1.05 } if {$tempo(xscale) == "doy"} { set xmin -0.05 set xmax 365.3 } } # save the best-fit period as a global switch $tempo(unit) { s { set tempo(P) [expr 1.0e0/$tempo(F0)] } ms { set tempo(P) [expr 1.0e3/$tempo(F0)] } \\gms { set tempo(P) [expr 1.0e6/$tempo(F0)] } } # set scale on right-hand axis to turns/milliturns set turns [expr abs($ymax/$tempo(P))] if [expr $turns < 0.05] { set turns [expr $turns*1000.0] set tunit milliperiods } else { set tunit periods } set temp $ymax global xopt yopt set xopt 1bcnst set yopt cmstv limits $xmin $xmax -$turns $turns box pglab "" "" "" "Residual ($tunit)" set ymax $temp # now set the limits and plot residuals set frequencies [resid2 freq] ; # get TOA frequencies limits $xmin $xmax -$ymax $ymax set yopt bvnst box set tmp $erycol set erycol 1 set barlo [lmath $ydata - $erydat] set barhi [lmath $ydata + $erydat] for {set i 0} {[expr $i < [llength $xdata]]} {incr i} { # set the pen colour according to the observing frequency (MHz) set nu [lindex $frequencies $i] if {[expr $nu < 500.0]} { pen red } elseif {[expr $nu >= 500.0] && [expr $nu < 1000.0]} { pen orange } elseif {[expr $nu >= 1000.0] && [expr $nu < 2000.0]} { pen blue } elseif {[expr $nu >= 2000.0] && [expr $nu < 3000.0]} { pen green } elseif {[expr $nu >= 3000.0]} { pen cyan } pgpt 1 [lindex $xdata $i] [lindex $ydata $i] 17 pgerry 1 [lindex $xdata $i] [lindex $barlo $i] [lindex $barhi $i] 1.0 pen black } #points set erycol $tmp baseline 0.0 ylabel "$tempo(resid) Residual ($tempo(unit))" title "" catch {lab} set yopt bcnst # if {$tempo(FAKE) && [file exists expected]} { # read expected # line # } pgebuf # enable various buttons on the main panel after first run through if {$tempo(plotdisabled)} { foreach widget ".tempo.input.upd .tempo.input.prefit .tempo.input.postfit .tempo.input.days\ .tempo.input.mjd .tempo.input.doy .tempo.input.date .tempo.input.index\ .tempo.input.ps .tempo.input.setepoch" { $widget configure -state normal } set tempo(plotdisabled) 0 } # enable residial plot vs orbital phase if this is a binary pulsar if {[sum [resid2 orphi]] == "0.0"} { .tempo.input.orphi configure -state disabled } else { .tempo.input.orphi configure -state normal } # save MIDpoint (to the nearest day) for use with CENTRE button set mjds [lsort [resid2 mjd]] set tempo(CENTRE) \ [format %.0f [expr 0.5*([lindex $mjds 0]+[lindex $mjds end])]] .tempo.input.centre configure -state normal .tempo.input.dparms configure -state normal .tempo.input.advanced.ideal configure -state normal .tempo.input.advanced.restore configure -state normal # update message bar with fit stats if {$tempo(unit) == "\\gms"} {set unit us} else {set unit $tempo(unit)} set span [format %.1f [expr [lindex $mjds end] - [lindex $mjds 0]]] show_message "PSR $tempo(PSR) - [llength $ydata] TOAs spanning $span days,\ post-fit RMS = $tempo(rmsvalue) $unit" set rms [format "%.1f" [expr [resid2 rms]*1.0e6]] .tempo.parms configure -text \ "[llength $ydata] TOAs over $span days, post-fit RMS = $rms us" } ################################################################################ proc tempo_fitpar {key} { switch $key { A1 - E - EPS1 - EPS2 - TASC - T0 - PB - OM - OMDOT - XDOT - EDOT - GAMMA - SINI - PBDOT - M2 - RAJ - DECJ - RA - DEC - LAMBDA - BETA - PMLAMBDA - PMBETA - PMRA - PMDEC - PMLAMBDA - PMBETA - PMRV - DM - PX - GLEP_1 - GLPH_1 - GLF0_1 - GLF1_1 - GLF0D_1 - GLTD_1 - GLEP_2 - GLPH_2 - GLF0_2 - GLF1_2 - GLEP_3 - GLPH_3 - GLF0_3 - GLF1_3 - F - F0 - F1 - F2 {return 1} default {return 0} } } ################################################################################ proc tempo_dispar {key} { switch $key { CLK - EPHEM - PSRJ - PSRB - PSR - PEPOCH - GAIN - IBOOT - NDDM - BINARY {return 1} default {return 0} } } ################################################################################ proc tempo_cursor {} { global tempo xdata ydata xmin xmax ymin ymax pgplot update idletasks set widget .tempo.input.timfile.txt set k [set replot 0] while {$k != "X"} { curs x y k set idx [lindex [identify $x $y] 0] set eus [expr [lindex $tempo(etoa) $idx]/$tempo(EFAC)] set result [$widget search [format %.2f $eus] 0.0] if {[llength $result] == 0} { puts "could not find line in timfile..." set tempo(cursor) 0 return } scan $result %d.%d l c switch $k { A { $widget see $l.0 update idletasks set line [$widget get $l.0 $l.end] #set prffile [format "%.0f.%.0f.%03d.prf" \ # [lindex $line 4] [lindex $line 3] [lindex $line 1]] set prffile [lindex [set line [$widget get $l.0 $l.end]] 0] if [file exists $prffile] { set x $xdata set x1 $xmin set x2 $xmax set y $ydata set y1 $ymin set y2 $ymax set xdata [set ydata ""] set i 0 switch [lindex [split $prffile .] end] { prf { set binvalues [cread $prffile 2] } FT { set binvalues [exec treduce -E $prffile] } } foreach bin $binvalues { incr i lappend xdata $i lappend ydata $bin } pgslct $pgplot($tempo(otherplot)) adv range $xdata xmin xmax range $ydata ymin ymax limits $xmin $xmax $ymin $ymax line limits 0 1 0 1.1 pgtext -0.05 1.25 $prffile pgtext -0.05 1.15 "MJD [format %.3f [lindex $line 4]]\ [format %.1f [lindex $line 3]] MHz" pgslct $pgplot($tempo(resplot)) set xdata $x set xmin $x1 set xmax $x2 set ydata $y set ymin $y1 set ymax $y2 } else { puts "profile $prffile not found!" set tempo(cursor) 0 return } } D { if ![commentline $widget $l] {pgsci 0} pgpt 1 [lindex $xdata $idx] [lindex $ydata $idx] 24 pgsci 1 $widget see $l.0 update idletasks } s { set xmin $x set replot 1 pgmove $xmin $ymin pgdraw $xmin $ymax } f { set xmax $x plotresiduals customlimits set replot 0 } . { puttextline $widget $l "PHASE +1\n" $widget see $l.0 update idletasks } , { puttextline $widget $l "PHASE -1\n" $widget see $l.0 update idletasks } } } set tempo(cursor) 0 if {$replot} {plotresiduals customlimits} } ################################################################################ # This procedure is called whenever cursor motion is detected in the # the image widget. It displays the world coordinates of the cursor # in previously created label widgets. # # Input: # pg The image pgplot widget. # x y The X-window coordinates of the cursor. #----------------------------------------------------------------------- proc report_motion {pg x y} { global tempo set tempo(xcurs) [$pg world x $x] set tempo(ycurs) [$pg world y $y] } ################################################################################ proc start_tempo_pgplot {} { global tempo pgplot frame .tempo.plot pack .tempo.plot -in .tempo -expand 1 -side bottom set tempo(resplot) [newpgplot .tempo.plot residuals] .tempo.plot.residuals.residuals configure -foreground black .tempo.plot.residuals.residuals configure -width $tempo(plotwidth) .tempo.plot.residuals.residuals configure -height $tempo(plotheight) .tempo.plot.residuals.residuals configure -maxcolors 16 bind .tempo.plot.residuals.residuals {report_motion %W %x %y} # for some reason, this routine is required rather than a direct # command in the Button-2 binding below ??? anyway - this works! proc twodp {f} { return [format %.1f $f] } bind .tempo.plot.residuals.residuals { global tempo xmin xmax ymin ymax set x0 $tempo(xcurs) set y0 $tempo(ycurs) set result [pgband 2 1 $x0 $y0] set x1 [lindex $result 0] set y1 [lindex $result 1] set xmin [min $x0 $x1] set xmax [max $x0 $x1] set ymin [min $y0 $y1] set ymax [max $y0 $y1] set xdif [expr abs($xmin-$xmax)] set ydif [expr abs($ymin-$ymax)] if {[expr $xdif > 0.1] && [expr $ydif > 0.1]} { plotresiduals customlimits } } bind .tempo.plot.residuals.residuals { comment_uncomment_with_cursor } proc comment_uncomment_with_cursor {} { global tempo xdata ydata set widget .tempo.input.timfile.txt set result [identify $tempo(xcurs) $tempo(ycurs)] set idx [lindex $result 0] set result [$widget search [lindex $tempo(TOAS) $idx] 0.0] if {[llength $result] == 0} { show_message "HELP! the cursor selection didn't work :(" } else { set l [lindex [split $result .] 0] if {[commentline $widget $l]} { pgpt 1 [lindex $xdata $idx] [lindex $ydata $idx] 24 show_message \ "Commented line $l from $tempo(timfile). This will take effect next time you run TEMPO" } else { pgsci 0 pgpt 1 [lindex $xdata $idx] [lindex $ydata $idx] 24 pgsci 1 show_message "Uncommented line $l from $tempo(timfile). This will take effect next time you run TEMPO" } $widget see $l.0 } update idletasks } bind .tempo.plot.residuals.residuals { tempo noplot plotresiduals customlimits } pgsch 2.5 pgscf 2 pgslw 4 pgsvp 0.1 0.9 0.19 0.99 adv # set tempo(otherplot) [newpgplot .tempo.plot other] # .tempo.plot.other.other configure -foreground black # .tempo.plot.other.other configure -width 10c # .tempo.plot.other.other configure -height 10c # .tempo.plot.other.other configure -maxcolors 16 # pgsch 2.5 # pgscf 2 # pgslw 6 # pgsvp 0.1 0.9 0.175 0.975 # adv } ################################################################################ proc delete_all_instances_of {string widget} { while {[set instance [$widget search $string 0.0]] != ""} { scan $instance %d.%d l c $widget delete $l.0 [expr $l+1].0 } } ################################################################################ # this will restore all commented points in the current timfile proc uncomment_all_TOAs {} { global tempo set widget .tempo.input.timfile.txt savetempo set restored 0 set file [open $tempo(timfile) r] while {[readline $file line]} { set first [lindex $line 0] if {$first == "C"} { incr restored set result [$widget search $line 0.0] set l [lindex [split $result .] 0] commentline $widget $l } } close $file if {$restored != "0"} { show_message "Restored $restored commented TOAs to the list..." } else { show_message "No commented TOAs found in the file..." } update idletasks } ################################################################################ proc update_ephemeris {} { global tempo set parfile [lindex [.tempo.input.parfile.txt get 1.0 1.end] 1].par if [file exists $parfile] { exec cp $parfile $tempo(parfile) loadpar delete_all_instances_of PHASE .tempo.input.timfile.txt tempo show_message "Input ephemeris now up-to-date..." } } ################################################################################ proc show_message {message} { .tempo.input.message configure -text $message .tempo.input.message configure -fg blue } ################################################################################ proc show_hint {message} { .tempo.input.message configure -text $message .tempo.input.message configure -fg red } ################################################################################ proc tempotkhelp {file} { puts $file " TempoTk - a graphical interface to the TEMPO pulsar timing package\n\ \n\ top left - display and manage your .tim and .par files \n\ top right - used to display TEMPO output files and documentation \n\ bottom - region used for plotting pre and post-fit residuals \n\ \n\ Plot commands: \n\ \n\ Zoom into a region of TOAs - Left-Click and drag \n\ Comment/Uncomment a TOA - Middle-Click on a TOA \n\ Rerun TEMPO within a zoomed region - Right-Click inside plot \n\ \n\ Timfile commands: \n\ \n\ SKIP/NOSKIP inside the tim file - Select lines then Middle-Click \n\ JUMP/JUMP inside the tim file - Select lines then Right-Click \n\ END statement in the tim file - Place cursor then Middle-Click \n\ Yank whole line from tim file - Place cursor then Right-Click \n\ Recover/paste in yanked line - Place cursor then \n\ PHASE +1/-1 - Place cursor then a/s \n\ Swap current and next lines - Place cursor then \n\ \n\ Parfile commands: \n\ \n\ Fit/Hold Constant a parameter - Left-Double-Click in parfile \n\ Rerun TEMPO - Right-Click in parfile \n\ Update input ephemeris - Middle-Click in parfile " } ################################################################################ if {$argv != ""} { set filestem [lindex $argv 0] if {[file exists "$filestem.par"] && [file exists "$filestem.tim"]} { # a stem.tim and stem.par file have been found! set tempo(parfile) "$filestem.par" set tempo(timfile) "$filestem.tim" } elseif {[file exists $filestem]} { # test to see if it is an ephemeris + TOA file set test [open $filestem] readline $test line if {$line == "HEAD" || $line == "HEADER"} { # it is! split it up into a .par and .tim file set stem [lindex [split $filestem .] 0] set tempo(parfile) "$stem.par" set parf [open $tempo(parfile) w] while {[readline $test line]} { if {$line == "TOA"} {break} if {[lindex $line 0] == "PSRJ"} { set param PSR } else { set param [lindex $line 0] } set fit "" if {[lindex $line 2] == "1"} {set fit 1} puts $parf "$param [lindex $line 1] $fit" } close $parf set tempo(timfile) "$stem.tim" set timf [open $tempo(timfile) w] while {[readline $test line]} { puts $timf $line } close $timf } } else { # neither of the above two options were found puts "TempoTk: no par/tim files found and/or TEMPO file not parsed" exit } } else { puts "" puts "TempoTk - a graphical user interface to TEMPO" puts "" puts "usage: tempotk filename (screensize)" puts "" puts "where filename is mandatory and may be either:" puts "" puts "1: the STEM of the .tim/par files." puts " For example, to run TempoTk on test.tim and test.par" puts " you would invoke the program as \"tempotk test\"" puts "2: the name of a complete TEMPO input file." puts " For example, to run TempoTk on test.tempo" puts " you would invoke the program as \"tempotk test.tempo\"" puts " N.B. that in this case, TempoTk will parse test.tempo" puts " into two files test.tim and test.par which it will then" puts " work on. Your input file will remain unchanged!" puts "" puts "screensize is optional and may be:" puts "" puts "small - suitable for use on laptops, etc" puts "medium - suitable for use on most workstations (default)" puts "large - suitable for use on big screens!" puts "" exit } if {[llength $argv] == "1"} { set screensize medium } else { set screensize [lindex $argv 1] } switch $screensize { small { set tempo(dpfont) {Helvetica -12} set tempo(mfont) {Courier -10} set tempo(bfont) {Helvetica -3} set tempo(pepwidth) 4 set tempo(plotwidth) 26.c set tempo(plotheight) 8c set tempo(timfwidth) 68 set tempo(timfheight) 7 set tempo(timffont) {Courier 10} set tempo(parffont) "Courier 10" set tempo(parfwidth) 35 set tempo(parfheight) 3 set tempo(savewidth) 13 set tempo(saveheight) 3 set tempo(outpwidth) 52 set tempo(outpheight) 17 set tempo(outpfont) {Courier 10} } medium { set tempo(dpfont) {Helvetica -18} set tempo(bfont) {Helvetica -12 bold} set tempo(mfont) {Helvetica -12 bold} set tempo(pepwidth) 6 set tempo(plotwidth) 32.5c set tempo(plotwidth) 31.1c set tempo(plotheight) 12c set tempo(timfwidth) 80 set tempo(timfheight) 15 set tempo(timffont) {Courier 10} set tempo(parffont) "Courier -12" set tempo(parfwidth) 33 set tempo(parfheight) 11 set tempo(savewidth) 16 set tempo(saveheight) 8 set tempo(outpwidth) 70 set tempo(outpheight) 28 set tempo(outpheight) 26 set tempo(outpfont) {Courier 10} } large { set tempo(dpfont) {Helvetica -18} set tempo(bfont) {Helvetica -12 bold} set tempo(mfont) {Helvetica -12 bold} set tempo(pepwidth) 6 set tempo(plotwidth) 40c set tempo(plotheight) 13c set tempo(timfwidth) 80 set tempo(timfheight) 20 set tempo(timffont) {Courier -12} set tempo(parffont) "Courier -12" set tempo(parfwidth) 37 set tempo(parfheight) 11 set tempo(savewidth) 20 set tempo(saveheight) 8 set tempo(outpwidth) 80 set tempo(outpheight) 29 set tempo(outpfont) {Courier -12} } default { puts "TempoTk: invalid screen size option, specify either small, medium or large" exit } } toplevel .tempo wm title .tempo \ "Welcome to TempoTk - a graphical user interface to TEMPO..." wm iconname .tempo TempoTk frame .tempo.top pack .tempo.top -in .tempo frame .tempo.input pack .tempo.input -in .tempo.top -side left # widget containg the TOAs frame .tempo.input.timxview pack .tempo.input.timxview -in .tempo.input -fill x -expand 1 scrollbar .tempo.input.timxview.scr -command ".tempo.input.timfile.txt xview" \ -orient horizontal frame .tempo.input.timfile pack .tempo.input.timfile -in .tempo.input -fill x -expand 1 text .tempo.input.timfile.txt -width $tempo(timfwidth) -font $tempo(timffont) \ -yscrollcommand ".tempo.input.timfile.ysc set" -height $tempo(timfheight) \ -xscrollcommand ".tempo.input.timxview.scr set" -wrap none bind .tempo.input.timfile.txt { set widget .tempo.input.timfile.txt commentline $widget [textlinenum $widget] catch { tkwait visibility .tempo selection clear } } bind .tempo.input.timfile.txt { selection clear update idletasks } bind .tempo.input.timfile.txt { set widget .tempo.input.timfile.txt getselected $widget first last selection clear update idletasks if {$first != "0" && $last != "0"} { puttextline $widget $first SKIP\n puttextline $widget [expr $last+1] NOSKIP\n } else { puttextline $widget [textlinenum $widget] END\n } catch { tkwait visibility .tempo } } bind .tempo.input.timfile.txt { set widget .tempo.input.timfile.txt getselected $widget first last selection clear update idletasks if {$first != "0" && $last != "0"} { puttextline $widget $first JUMP\n puttextline $widget [expr $last+1] JUMP\n } else { deleteline $widget [textlinenum $widget] } catch { tkwait visibility .tempo } } bind .tempo.input.timfile.txt a { set widget .tempo.input.timfile.txt getselected $widget first last if {$first == "0" && $last == "0"} { puttextline $widget [textlinenum $widget] "PHASE +1\n" } catch { tkwait visibility .tempo selection clear } } bind .tempo.input.timfile.txt s { set widget .tempo.input.timfile.txt getselected $widget first last if {$first == "0" && $last == "0"} { puttextline $widget [textlinenum $widget] "PHASE -1\n" } catch { tkwait visibility .tempo selection clear } } set tempo(deleted) "" bind .tempo.input.timfile.txt { set widget .tempo.input.timfile.txt pasteline $widget [textlinenum $widget] } bind .tempo.input.timfile.txt { set widget .tempo.input.timfile.txt set next [expr [set line [textlinenum $widget]]+1] set text [$widget get $line.0 $line.end] deleteline $widget $line puttextline $widget $next $text\n } pack .tempo.input.timfile.txt -side left -in .tempo.input.timfile -fill x -expand 1 -fill y scrollbar .tempo.input.timfile.ysc -command ".tempo.input.timfile.txt yview" pack .tempo.input.timfile.ysc -side right -fill y -in .tempo.input.timfile label .tempo.input.message -font $tempo(mfont) pack .tempo.input.message -in .tempo.input frame .tempo.input.top pack .tempo.input.top -in .tempo.input -fill x -expand 1 set hint(.tempo.input.save) "This button saves your current tim/par files" button .tempo.input.save -font $tempo(bfont) -text SAVE -command { savetempo set parstem [string trimright $tempo(parfile) .par] set timstem [string trimright $tempo(timfile) .tim] set i 97 set e a while {[file exists $parstem$e.par] && [file exists $timstem$e.tim]} { incr i if {$i == "123"} {error "large numbers of par/tim files..."} set e [format %c $i] } exec cp $tempo(parfile) $parstem$e.par exec cp $tempo(timfile) $timstem$e.tim update_tempo_saved show_message "Your current par/tim files are saved as: $parstem$e.par $timstem$e.tim" } set hint(.tempo.input.upd) "Sets TEMPO's output par file to be your input. Consider SAVEing before doing this!" button .tempo.input.upd -text UPDATE -font $tempo(bfont) -state disabled -command update_ephemeris set hint(.tempo.input.tlb) "Reloads the TOAs in from the file. In case you've screwed up and want to recover!" button .tempo.input.tlb -font $tempo(bfont) -text TIM -command loadtim entry .tempo.input.tim -textvariable tempo(timfile) -width 4 bind .tempo.input.tim loadtim proc loadtim {args} { global tempo if {$args != ""} { set file [open $args] } else { set file [open $tempo(timfile)] } .tempo.input.timfile.txt delete 1.0 end while {[readline $file line]} { if {$line != ""} { if {[lindex $line 0] == "MODE"} { set tempo(MODE) [lindex $line 1] } elseif {[lindex $line 0] == "EFAC"} { set tempo(EFAC) [lindex $line 1] } else { .tempo.input.timfile.txt insert end $line\n } } } close $file } set hint(.tempo.input.plb) "Reloads input pars in from the file. In case you've screwed up and want to recover!" button .tempo.input.plb -text PAR -font $tempo(bfont) -command loadpar entry .tempo.input.par -textvariable tempo(parfile) -width 4 bind .tempo.input.par loadpar proc loadpar {args} { global tempo if {$args != ""} { set file [open $args] } else { set file [open $tempo(parfile)] } .tempo.input.parfile.txt delete 1.0 end while {[readline $file line]} { set line [string range $line 0 30] set key [lindex $line 0] if {[tempo_dispar $key] || [tempo_fitpar $key]} { .tempo.input.parfile.txt insert end $line\n if {$key == "PSRJ"} {set key PSR} set tempo($key) [lindex $line 1] } if {$key == "NITS"} {set tempo(NITS) [lindex $line 1]} } close $file } set hint(.tempo.input.setepoch) "Runs TEMPO to reset the epoch of period. You may consider a SAVE beforehand!" button .tempo.input.setepoch -text EPOCH -font $tempo(bfont) -command {setepoch $tempo(PEPOCH)}\ -state disabled entry .tempo.input.pepoch -textvariable tempo(PEPOCH) -width $tempo(pepwidth) set hint(.tempo.input.centre) "Runs TEMPO to centre the epoch of period. You may consider a SAVE beforehand!" button .tempo.input.centre -font $tempo(bfont) -text CENTRE -state disabled \ -command { setepoch $tempo(CENTRE) show_message \ "The epoch of period in the ephemeris has now been set to the centre MJD: $tempo(EPOCH)" } packin .tempo.input.top .tempo.input.save .tempo.input.upd \ .tempo.input.tlb .tempo.input.plb \ .tempo.input.setepoch .tempo.input.pepoch \ .tempo.input.centre frame .tempo.input.parframe pack .tempo.input.parframe -in .tempo.input -fill x -expand 1 frame .tempo.input.parfile frame .tempo.input.advanced frame .tempo.input.saved pack .tempo.input.parfile .tempo.input.advanced .tempo.input.saved -in .tempo.input.parframe \ -fill x -expand 1 -fill y -side left text .tempo.input.parfile.txt -width $tempo(parfwidth) -font $tempo(parffont) \ -yscrollcommand ".tempo.input.parfile.scr set" -height $tempo(parfheight) bind .tempo.input.parfile.txt { selection clear update idletasks } bind .tempo.input.parfile.txt { set name .tempo.input.parfile.txt if [tempo_fitpar [lindex [set text [gettextline $name]] 0]] { zaptextline $name [set line [textlinenum $name]] switch [lindex $text 2] { 1 {set text [string range $text 0 25]} 0 - default {set text "[string range $text 0 25] 1"} } puttextline $name $line $text } catch { tkwait visibility .tempo selection clear } } bind .tempo.input.parfile.txt { update_ephemeris } bind .tempo.input.parfile.txt { .tempo.input.run configure -relief sunken update idletasks catch [tempo] .tempo.input.run configure -relief raised } pack .tempo.input.parfile.txt -side left -in .tempo.input.parfile -fill x -expand 1 -fill y scrollbar .tempo.input.parfile.scr -command ".tempo.input.parfile.txt yview" pack .tempo.input.parfile.scr -side right -fill y -in .tempo.input.parfile checkbutton .tempo.input.advanced.hints -font $tempo(bfont) -text "Get hints" -variable tempo(hints)\ -relief raised -pady 4 -command { if {$tempo(hints)} { show_hint \ "Move the mouse over a button/window to get one-line hints here..." } else { show_message \ "One-line hints mode deactivated... Good Luck!" } } pack .tempo.input.advanced.hints -in .tempo.input.advanced -fill x -expand 1 set tempo(MODE) 0 set tempo(EFAC) 1.0 set tempo(NITS) 1 set hint(.tempo.input.advanced.mode) \ "This will run TEMPO with/without TOA weighting (i.e. toggle the MODE command)" checkbutton .tempo.input.advanced.mode -font $tempo(bfont) -text "Weight fit" -variable tempo(MODE)\ -relief raised -pady 4 pack .tempo.input.advanced.mode -in .tempo.input.advanced -fill x -expand 1 if {$screensize != "small"} { frame .tempo.input.advanced.efac pack .tempo.input.advanced.efac -in .tempo.input.advanced -fill x -expand 1 label .tempo.input.advanced.efac.lab -text EFAC: set hint(.tempo.input.advanced.efac.val) "Multiply all TOA errors by this factor. Only relevent when TOA weights selected" entry .tempo.input.advanced.efac.val -textvariable tempo(EFAC) -width 4 packin .tempo.input.advanced.efac .tempo.input.advanced.efac.lab .tempo.input.advanced.efac.val frame .tempo.input.advanced.nits pack .tempo.input.advanced.nits -in .tempo.input.advanced -fill x -expand 1 label .tempo.input.advanced.nits.lab -text NITS: set hint(.tempo.input.advanced.nits.val) "Run TEMPO NITS times in succession using output ephem as starting point each time" entry .tempo.input.advanced.nits.val -textvariable tempo(NITS) -width 4 packin .tempo.input.advanced.nits .tempo.input.advanced.nits.lab .tempo.input.advanced.nits.val } set hint(.tempo.input.advanced.restore) "This button will restore all TOAs from your tim file that have been commented" button .tempo.input.advanced.restore -font $tempo(bfont) -text Restore -command uncomment_all_TOAs \ -state disabled pack .tempo.input.advanced.restore -in .tempo.input.advanced -fill x set hint(.tempo.input.advanced.ideal) "This will set the weights so that Chisqr / degrees of freedom is ~ unity" button .tempo.input.advanced.ideal -font $tempo(bfont) -state disabled \ -text Ideal-Chisqr -relief raised -pady 4\ -command ideal_chisqr pack .tempo.input.advanced.ideal -in .tempo.input.advanced -fill x listbox .tempo.input.saved.lis -width $tempo(savewidth) -font {Courier 10} \ -height $tempo(saveheight) -yscrollcommand ".tempo.input.saved.scr set" bind .tempo.input.saved.lis { if [catch {set stem [selection get]}] {return} loadtim $stem.tim loadpar $stem.par show_message "TempoTk - loaded par/tim files from: $stem.par $stem.tim" } bind .tempo.input.saved.lis { if [catch {set stem [selection get]}] {return} set rm1 [catch {exec rm -f $stem.tim}] set rm2 [catch {exec rm -f $stem.par}] if {!$rm1 && !$rm2} { show_message "$stem.par and $stem.tim have been zapped!" } update_tempo_saved } proc update_tempo_saved {} { if ![winfo exists .tempo.input.saved.lis] {return} .tempo.input.saved.lis delete 0 end set parfiles [glob *.par] if ![llength $parfiles] {return} foreach par $parfiles { set stem [lindex [split $par .] 0] if [file exists $stem.tim] { .tempo.input.saved.lis insert end $stem } } .tempo.input.saved.lis see end } update_tempo_saved pack .tempo.input.saved.lis -side left -fill x -expand 1 -fill y -in .tempo.input.saved scrollbar .tempo.input.saved.scr -command ".tempo.input.saved.lis yview" pack .tempo.input.saved.scr -side right -fill y -in .tempo.input.saved frame .tempo.input.main pack .tempo.input.main -in .tempo.input -fill x -expand 1 set hint(.tempo.input.run) "This button will run TEMPO on your current tim/par files" button .tempo.input.run -font $tempo(bfont) -command tempo -text "FIT!" set hint(.tempo.input.tkhelp) "This button will tell you all about the various TempoTk short cuts" button .tempo.input.tkhelp -font $tempo(bfont) -text "TempoTk help" -command { set file [open tempotk.help w] tempotkhelp $file close $file set file [open tempotk.help r] .tempo.output.lis delete 0 end while {[readline $file line]} { .tempo.output.lis insert end $line } close $file exec rm -f tempotk.help show_message "TempoTk documentation pasted on the top-right window" } set hint(.tempo.input.help) "This button will show you the TEMPO documentation" button .tempo.input.help -font $tempo(bfont) -text "TEMPO help" -command { set file [open $env(IMPULSE)/docs/tempo.txt] .tempo.output.lis delete 0 end while {[readline $file line]} { .tempo.output.lis insert end $line } close $file show_message "TEMPO documentation pasted on the top-right window" } set hint(.tempo.input.dparms) "Calculate characteristic age, surface B-field and Edot from P and Pdot" button .tempo.input.dparms -font $tempo(bfont) -text DPARMS -state disabled -command { # update derived parameter window set psec [expr 1.0/$tempo(F0)] set pdot [expr -1.0*$psec*$psec*$tempo(F1)] if {[expr $pdot > 0.0]} { set age [expr 0.5*$psec/$pdot/365.25/86400.0] if {[expr $age > 1.0e9]} { set age "[format %.1f [expr $age/1.0e9]] Gyr" } elseif {[expr $age > 1.0e6]} { set age "[format %.1f [expr $age/1.0e6]] Myr" } elseif {[expr $age > 1.0e3]} { set age "[format %.1f [expr $age/1.0e3]] kyr" } set b0 "[format %.1e [expr sqrt($psec*$pdot)*3.2e19]] G" set edot \ "[format %.1e [expr $pdot/($psec*$psec*$psec)*3.948e46]] erg/s" .tempo.parms configure -text "Age: $age, B0: $b0, Edot: $edot" show_message "Derived parameters displayed on middle-right panel. Don't take 'em too literally, ok?" } else { show_message "No Pdot measured yet! Get busy on that timing fit, dude!" } } set hint(.tempo.input.ps) "Generate a PostScript output of your residuals suitable for publication" button .tempo.input.ps -font $tempo(bfont) -text Hardcopy -state disabled -command { global pgplot tempo set psfile [lindex [split $tempo(parfile) .] 0].ps set tempo(psfile) [pgopen $psfile/ps] pgscf 2 pgsch 1.5 pgsvp 0.2 0.8 0.2 0.8 plotresiduals customlimits pgclos pgslct $pgplot($tempo(resplot)) plotresiduals customlimits show_message "publication quality PostScript output written to $psfile..." } set hint(.tempo.input.quit) "Exit from TempoTk gracefully..." button .tempo.input.quit -font $tempo(bfont) -text Quit -command { foreach file "tempo.lis tempo.out matrix.tmp resid2.tmp" { if {[file exists $file]} {exec rm -f $file} } exit } packin .tempo.input.main .tempo.input.run .tempo.input.tkhelp \ .tempo.input.help .tempo.input.dparms .tempo.input.ps \ .tempo.input.quit frame .tempo.input.plot pack .tempo.input.plot -in .tempo.input -fill x -expand 1 set tempo(resid) Pre-fit set tempo(plotdisabled) 1 set hint(.tempo.input.prefit) "Display pre-fit residuals from TEMPO" radiobutton .tempo.input.prefit -font $tempo(bfont) -text Pre -variable tempo(resid) \ -value Pre-fit -state disabled \ -command plotresiduals -relief raised -pady 4 set hint(.tempo.input.postfit) "Display post-fit residuals from TEMPO" radiobutton .tempo.input.postfit -font $tempo(bfont) -text Post -variable tempo(resid) \ -value Post-fit -state disabled \ -command plotresiduals -relief raised -pady 4 set tempo(xscale) days set hint(.tempo.input.days) "Set the x-axis on the residual plot to be in days since the first TOA" radiobutton .tempo.input.days -font $tempo(bfont) -text DAYS -variable tempo(xscale) -value days \ -command plotresiduals -relief raised -pady 4 -state disabled set hint(.tempo.input.mjd) "Set the x-axis on the residual plot to be modified Julian date (MJD)" radiobutton .tempo.input.mjd -font $tempo(bfont) -text MJD -variable tempo(xscale) -value mjd \ -command plotresiduals -relief raised -pady 4 -state disabled set hint(.tempo.input.date) "Set the x-axis on the residual plot to be calendar date (e.g. 2000.5)" radiobutton .tempo.input.date -font $tempo(bfont) -text Date -variable tempo(xscale) -value date \ -command plotresiduals -relief raised -pady 4 -state disabled set hint(.tempo.input.doy) "Set the x-axis on the residual plot to be day of the year (i.e. 1-365)" radiobutton .tempo.input.doy -font $tempo(bfont) -text DOY -variable tempo(xscale) -value doy \ -command plotresiduals -relief raised -pady 4 -state disabled set hint(.tempo.input.index) "Set the x-axis on the residual plot to be TOA index (index of first TOA=1)" radiobutton .tempo.input.index -font $tempo(bfont) -text IDX -variable tempo(xscale) -value index \ -command plotresiduals -relief raised -pady 4 -state disabled set hint(.tempo.input.orphi) "Set the x-axis on the residual plot to be orbital phase (mean anomaly)" radiobutton .tempo.input.orphi -font $tempo(bfont) -text ORB -variable tempo(xscale) -value orphi \ -command plotresiduals -relief raised -pady 4 -state disabled packin .tempo.input.plot .tempo.input.prefit .tempo.input.postfit .tempo.input.days \ .tempo.input.mjd .tempo.input.date .tempo.input.doy .tempo.input.index .tempo.input.orphi frame .tempo.outpars pack .tempo.outpars -in .tempo.top -side left -fill x -expand 1 frame .tempo.output pack .tempo.output -in .tempo.outpars listbox .tempo.output.lis -height $tempo(outpheight) -width $tempo(outpwidth)\ -relief groove -yscrollcommand ".tempo.output.scr set" -font $tempo(outpfont) \ -xscrollcommand ".tempo.scroll.xsc set" pack .tempo.output.lis -in .tempo.output -fill x -expand 1 -side left scrollbar .tempo.output.scr -command ".tempo.output.lis yview" pack .tempo.output.scr -side right -fill y -in .tempo.output frame .tempo.scroll pack .tempo.scroll -in .tempo.outpars -fill x -expand 1 scrollbar .tempo.scroll.xsc -command ".tempo.output.lis xview" -orient horizontal pack .tempo.scroll.xsc -in .tempo.scroll -fill x -expand 1 label .tempo.parms -text "RMS values from fits and DPARMS displayed here" -fg blue -font $tempo(dpfont) pack .tempo.parms -in .tempo.outpars -fill y -expand 1 if {$tempo(parfile) != ""} {loadpar} if {$tempo(timfile) != ""} {loadtim} start_tempo_pgplot .tempo.input.tkhelp invoke # set up hint messaging as mouse moves in and out of a widget bind all { if {[info exists hint(%W)] && $tempo(hints)} { catch {show_hint $hint(%W)} } } bind all { if {[info exists hint(%W)] && $tempo(hints)} { catch {.tempo.input.message configure -text ""} } } show_message "Welcome to TempoTk! Your TOAs are ready and waiting... hit \"Fit!\" to get started..." update idletasks ################################################################################