00001 ########################################################################3 00002 # imcontsub_test.py 00003 # 00004 # 00005 # Copyright (C) 2008, 2009 00006 # Associated Universities, Inc. Washington DC, USA. 00007 # 00008 # This scripts free software; you can redistribute it and/or modify it 00009 # under the terms of the GNU Library General Public License as published by 00010 # the Free Software Foundation; either version 2 of the License, or (at your 00011 # option) any later version. 00012 # 00013 # This library is distributed in the hope that it will be useful, but WITHOUT 00014 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00015 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00016 # License for more details. 00017 # 00018 # You should have received a copy of the GNU Library General Public License 00019 # along with this library; if not, write to the Free Software Foundation, 00020 # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00021 # 00022 # Correspondence concerning AIPS++ should be adressed as follows: 00023 # Internet email: aips2-request@nrao.edu. 00024 # Postal address: AIPS++ Project Office 00025 # National Radio Astronomy Observatory 00026 # 520 Edgemont Road 00027 # Charlottesville, VA 22903-2475 USA 00028 # 00029 # <author> 00030 # Shannon Jaeger (University of Calgary) 00031 # </author> 00032 # 00033 # <summary> 00034 # Test suite for the CASA imcontsub Task 00035 # </summary> 00036 # 00037 # <reviewed reviwer="" date="" tests="" demos=""> 00038 # </reviewed 00039 # 00040 # <etymology> 00041 # imcontsub_test stands for image momemnts test 00042 # </etymology> 00043 # 00044 # <synopsis> 00045 # imcontsub_test.py is a Python script that tests the correctness 00046 # of the imcontsub task in CASA. 00047 # 00048 # The tests include: 00049 # 1. Incorrect input for each paramter. Incorrect input includes 00050 # one input of the incorrect data type, out-of-bounds (where 00051 # applicable, and correct data type but non-sensical. 00052 # 2. A set of sample continuum subtractions with expected 00053 # output 00054 # 3. Calculating one example for each allowed fitorder 00055 # 4. Continuum subtraction with region selection on the sky, 00056 # channels, and stokes values, as well as using an input 00057 # region file. 00058 # 00059 # In the imcontsub task a specified continuum channel is subtracted 00060 # from spectral line data. 00061 # 00062 # The expected input is a spectral line image. Both a continuum 00063 # image and a continuum-subtracted spectral line are created as 00064 # output, as long as the user has provided filenames for them. 00065 # 00066 # By default the continuum subtraction is applied to the whole 00067 # image, however, if a region file is given and/or the user specifies 00068 # a box range, channels, or stokes values then the subtraction is 00069 # performed on this portion of the image only. 00070 # 00071 # </synopsis> 00072 # 00073 # <example> 00074 # # This test was designed to run in the CASA unit test system. 00075 # # This example shows who to run it manually from outside casapy. 00076 # casapy -c runUnitTest test_imcontsub 00077 # 00078 # or 00079 # 00080 # # This example shows who to run it manually from with casapy. 00081 # runUnitTest.main(['imcontsub_test']) 00082 # 00083 # </example> 00084 # 00085 # <motivation> 00086 # To provide a test standard to the imcontsub task to try and ensure 00087 # coding changes do not break the 00088 # </motivation> 00089 # 00090 # <todo> 00091 # Almost everything! 00092 # 00093 # imcontsub doesn't return anything currently on success or failure. 00094 # If this changes the tests will need to change to check for this. 00095 # The basic design of the tests is based on the immoments test which 00096 # returns an image tool upon success. 00097 # </todo> 00098 00099 #import random 00100 import os 00101 import shutil 00102 import casac 00103 from tasks import * 00104 from taskinit import * 00105 import unittest 00106 00107 # Input files 00108 list = ['g192_a2.image', 'g192_a2.image-2.rgn', 00109 'g192_a2.contfree', 'g192_a2.cont', 00110 'g192_a2.contfree.order1', 'g192_a2.cont.order1', 00111 'g192_a2.contfree.order2', 'g192_a2.cont.order2', 00112 'boxychans_cont.im', 'boxychans_line.im'] 00113 00114 # Tests the correctness of the imcontsub task in CASA including: 00115 # 1. Incorrect input for each paramter. Incorrect input includes 00116 # one input of the incorrect data type, out-of-bounds (where 00117 # applicable, and correct data type but non-sensical. 00118 # 2. Doing a couple continuum subtractions checking the 00119 # results with previous results. 00120 # 3. Doing continuum subtraction with fitorder from 1 to ?? 00121 # and verifying the results. 00122 # 4. Doing continuum subtraiong with region selection on the sky, 00123 # channels, and stokes values, as well as using an input 00124 # region file. 00125 # 00126 # Data used for this test includes: 00127 # 1. g192_a2.image 00128 00129 class imcontsub_test(unittest.TestCase): 00130 00131 def setUp(self): 00132 if(os.path.exists(list[0])): 00133 for file in list: 00134 os.system('rm -rf ' +file) 00135 00136 datapath = os.environ.get('CASAPATH').split()[0]+'/data/regression/g192redux/reference/' 00137 for file in list: 00138 os.system('cp -r ' +datapath + file +' ' + file) 00139 00140 00141 def tearDown(self): 00142 for file in list: 00143 os.system('rm -rf ' +file) 00144 os.system('rm -rf cont_*') 00145 os.system('rm -rf input_test*') 00146 os.system('rm -rf fit_test*') 00147 os.system('rm -rf line_*') 00148 00149 if os.path.exists( 'garbage.rgn' ): 00150 os.remove('garbage.rgn') 00151 00152 #################################################################### 00153 # Incorrect inputs to parameters. The parameters are: 00154 # imagename 00155 # linefile 00156 # contfile 00157 # fitorder 00158 # region 00159 # box 00160 # chans 00161 # stokes 00162 # 00163 # Returns True if successful, and False if it has failed. 00164 #################################################################### 00165 00166 def test_bad_imagename(self): 00167 """Test bad image name throws exception""" 00168 00169 exception = False 00170 try: 00171 imcontsub( 'g192', contfile='input_test_cont1', linefile='input_test_line1' ) 00172 exception = True 00173 except: 00174 exception = False 00175 self.assertTrue(exception) 00176 00177 def test_bad_linefile(self): 00178 """ Test bad line file name fails""" 00179 00180 # FIXME shouldn't a bad linefile name throw an exception? 00181 filename = 'input_test_line1' 00182 myfile = open(filename, mode="w") 00183 myfile.write("x") 00184 myfile.close() 00185 results = imcontsub( 'g192_a2.image', linefile=filename ) 00186 self.assertTrue(not results) 00187 00188 def test_bad_contfile(self): 00189 """ Test bad continuum file name fails""" 00190 00191 # FIXME shouldn't a bad linefile name throw an exception? 00192 filename = 'input_test_cont' 00193 myfile = open(filename, mode="w") 00194 myfile.write("x") 00195 myfile.close() 00196 results = imcontsub( 'g192_a2.image', contfile=filename ) 00197 self.assertTrue(not results) 00198 00199 def test_bad_fitorder(self): 00200 """Test bad fitorder fails""" 00201 00202 results=imcontsub( 'g192_a2.image', fitorder=-1, contfile='moment_test' ) 00203 self.assertTrue(not results) 00204 00205 results=imcontsub( 'g192_a2.image', fitorder=-2.3, contfile='moment_test' ) 00206 self.assertTrue(not results) 00207 00208 def test_bad_region(self): 00209 """ Test bad region parameter fails""" 00210 00211 results = imcontsub( 'g192_a2.image', region=7 ) 00212 self.assertTrue(not results) 00213 00214 filename = os.getcwd()+'/garbage.rgn' 00215 00216 results = imcontsub( 'g192_a2.image', region=filename) 00217 self.assertTrue(not results) 00218 00219 fp=open( filename, 'w' ) 00220 fp.writelines('This file does NOT contain a valid CASA region specification\n') 00221 fp.close() 00222 results = imcontsub( 'g192_a2.image', region=filename) 00223 self.assertTrue(not results) 00224 00225 00226 def test_bad_chans(self): 00227 """Test bad chans parameter causes failure""" 00228 00229 results = imcontsub( 'g192_a2.image', chans='-5' ) 00230 self.assertTrue(not results) 00231 00232 results = imcontsub( 'g192_a2.image', chans='-2' ) 00233 self.assertTrue(not results) 00234 00235 results = imcontsub( 'g192_a2.image', chans='-18' ) 00236 self.assertTrue(not results) 00237 00238 results = imcontsub( 'g192_a2.image', chans='45' ) 00239 self.assertTrue(not results) 00240 00241 results = imcontsub( 'g192_a2.image', chans='40' ) 00242 self.assertTrue(not results) 00243 00244 00245 def test_bad_box(self): 00246 """Test bad box parameter causes failure""" 00247 00248 results = imcontsub( 'g192_a2.image', box='-3,0,511,511' ) 00249 self.assertTrue(not results) 00250 00251 results = imcontsub( 'g192_a2.image', box='0,-3,511,511' ) 00252 self.assertTrue(not results) 00253 00254 results = imcontsub( 'g192_a2.image', box='-2,0,511,511' ) 00255 self.assertTrue(not results) 00256 00257 results = imcontsub( 'g192_a2.image', box='0,-2,511,511' ) 00258 self.assertTrue(not results) 00259 00260 results = imcontsub( 'g192_a2.image', box='0,0,512,511' ) 00261 self.assertTrue(not results) 00262 00263 results = imcontsub( 'g192_a2.image', box='0,0,511,512' ) 00264 self.assertTrue(not results) 00265 00266 results = imcontsub( 'g192_a2.image', box='0, 0,525,511' ) 00267 self.assertTrue(not results) 00268 00269 results = imcontsub( 'g192_a2.image', box='0,0,511,525' ) 00270 self.assertTrue(not results) 00271 00272 def test_bad_stokes(self): 00273 """Test bad stokes parameter causes failure""" 00274 results = imcontsub( 'g192_a2.image', stokes='Q' ) 00275 self.assertTrue(not results) 00276 00277 results = imcontsub( 'g192_a2.image', stokes='yellow' ) 00278 self.assertTrue(not results) 00279 00280 00281 00282 ## #################################################################### 00283 ## # Continuum subtraction correctness test. 00284 ## # 00285 ## # This test subtacts the continuum from the g192 data file 00286 ## # and compares the results (both continuum and spectral line 00287 ## # with subtracted continuum files) with pervious results. 00288 ## # 00289 ## # Random values are selected in the files and compared. 00290 ## # FIXME compare the entire arrays, not bloody random values 00291 ## # FIXED - replacing it with the equivalent but better test_fitorder(0) 00292 ## # sped the suite up from 1847s to 1194s on faraday.cv.nrao.edu. 00293 ## # 00294 ## # Returns True if successful, and False if it has failed. 00295 ## #################################################################### 00296 00297 ## def test_continuum(self): 00298 ## '''Imcontsub: Testing continuum sub correctness''' 00299 ## retValue = {'success': True, 'msgs': "", 'error_msgs': '' } 00300 ## casalog.post( "Starting imcontsub CONTINUUM SUB CORRECTNESS tests.", 'NORMAL2' ) 00301 00302 ## try: 00303 ## results=imcontsub( 'g192_a2.image', fitorder=0, contfile='cont_test_cont1', linefile='cont_test_line1' ) 00304 ## except Exception, err: 00305 ## retValue['success']=False 00306 ## retValue['error_msgs']=retValue['error_msgs']\ 00307 ## +"\nError: Unable to subtract continuum with a fit order of 0 "\ 00308 ## +"\n\t REULTS: "+str(results) 00309 ## else: 00310 ## if ( not os.path.exists( 'cont_test_cont1' ) or not os.path.exists( 'cont_test_line1' ) or not results ): 00311 ## retValue['success']=False 00312 ## retValue['error_msgs']=retValue['error_msgs']\ 00313 ## +"\nError: continuum 3 output files were NOT created." 00314 ## else: 00315 ## # Now that we know something has been done lets check some values 00316 ## # with previously created files to see if the values are the same. 00317 ## # We randomly pick 50 points (almost 10%) 00318 ## # FIXME lovely, yes let's pick random values to make sure any failures 00319 ## # cannot easily be reproduced, ugh 00320 ## for count in range(0,50): 00321 ## x = random.randint(0,511) 00322 ## y = random.randint(0,511) 00323 ## box=str(x)+','+str(y)+','+str(x)+','+str(y) 00324 ## chan = str(random.randint(0,39)) 00325 00326 ## line_prev_value={} 00327 ## line_cur_value={'empty':''} 00328 ## try: 00329 ## line_prev_value = imval( 'g192_a2.contfree', box=box, chans=chan, stokes='I' ) 00330 ## line_cur_value = imval( 'cont_test_line1', box=box, chans=chan, stokes='I' ) 00331 ## except: 00332 ## retValue['success']=False 00333 ## retValue['error_msgs']=retValue['error_msgs']\ 00334 ## +"\nError: Unable to compare spectral line files." 00335 ## else: 00336 ## #print "Spec line prev value: ", line_prev_value 00337 ## #print "spec line current value: ", line_cur_value 00338 ## casalog.post( "*** line_prev_value " + str(line_prev_value), 'WARN') 00339 ## casalog.post( "*** line_cur_value " + str(line_cur_value), 'WARN') 00340 ## if ( (line_prev_value['data'] != line_cur_value['data']).any() ): 00341 ## retValue['success'] = False 00342 ## retValue['error_msgs'] = '\nError: spectral line value differs with '\ 00343 ## + "previously calculated value at: "\ 00344 ## + "\t["+str(x)+','+str(y)+','+chan+',I].'\ 00345 ## + "\tvalues are "+str(line_prev_value)+" and "+str(line_cur_value) 00346 ## try: 00347 ## cont_prev_value = imval( 'g192_a2.cont', box=box, chans=chan, stokes='I' ) 00348 ## cont_cur_value = imval( 'cont_test_cont1', box=box, chans=chan, stokes='I' ) 00349 ## except: 00350 ## retValue['success']=False 00351 ## retValue['error_msgs']=retValue['error_msgs']\ 00352 ## +"\nError: Unable to compare continuum files." 00353 ## else: 00354 ## #print "Continuum prev value: ", cont_prev_value 00355 ## #print "Continuum current value: ", cont_cur_value 00356 ## if ( (cont_prev_value['data'] != cont_cur_value['data']).any() ): 00357 ## retValue['success'] = False 00358 ## retValue['error_msgs'] = '\nError: continuum value differs with '\ 00359 ## + "previously calculated value at: "\ 00360 ## + "\t["+str(x)+','+str(y)+','+chan+',I].' 00361 ## #+ "\tvalues are "+str(cont_prev_value)+" and "+str(cont_cur_value) 00362 00363 ## self.assertTrue(retValue['success'],retValue['error_msgs']) 00364 00365 00366 #################################################################### 00367 # Region selection correction test. 00368 # 00369 # This test selects a region for continuum subtraction. Checks 00370 # are done to make sure only the data in the selected region 00371 # changes. 00372 # 00373 # Returns True if successful, and False if it has failed. 00374 #################################################################### 00375 00376 # def test_region(self): 00377 # '''Imcontsub: Testing region parameters''' 00378 # retValue = {'success': True, 'msgs': "", 'error_msgs': '' } 00379 # casalog.post( "Starting imcontsub REGION tests.", 'NORMAL2' ) 00380 # 00381 # # First step get rid of all the old test files! 00382 # for file in os.listdir( '.' ): 00383 # if file.startswith( 'rgn_test_' ): 00384 # shutil.rmtree( file ) 00385 # 00386 # 00387 # 00388 # self.assertTrue(retValue['success'],retValue['error_msgs']) 00389 00390 00391 #################################################################### 00392 # Fitorder tests correctness test. 00393 # 00394 # This test subtacts the continuum from the g192 data file 00395 # for fitorder =1 and fitorder=2, note that fitorder=0 is 00396 # tested in the continuum test and valid/invalid inputs to 00397 # the fitorder paramter are tested in the input test. 00398 # 00399 # The results, image file contents, are compared with previously 00400 # created image files. 00401 # 00402 # Returns True if successful, and False if it has failed. 00403 #################################################################### 00404 00405 def test_fitorder(self): 00406 '''Imcontsub: testing fitorder correctness''' 00407 retValue = {'success': True, 'msgs': "", 'error_msgs': '' } 00408 casalog.post( "Starting imcontsub INPUT/OUTPUT tests.", 'NORMAL2' ) 00409 00410 # First step get rid of all the old test files! 00411 for file in os.listdir( '.' ): 00412 if file.startswith( 'fit_test_' ): 00413 shutil.rmtree( file ) 00414 00415 # TODO I'm just fixing the tests here to do something more reasonable since they were broken 00416 # and in bad need of rewriting (see the diff with the previous version before I made these 00417 # edits). This whole test file probably needs to be reviewed but of course time is tight so 00418 # I cannot do that now. 00419 00420 for order in xrange(2): 00421 contfile='fit_test_cont'+str(order) 00422 linefile='fit_test_line'+str(order) 00423 00424 if order > 0: 00425 oldcontfile='g192_a2.cont.order'+str(order) 00426 oldlinefile='g192_a2.contfree.order'+str(order) 00427 else: 00428 oldcontfile = 'g192_a2.cont' 00429 oldlinefile = 'g192_a2.contfree' 00430 00431 try: 00432 results = imcontsub('g192_a2.image', fitorder=order, contfile=contfile, linefile=linefile) 00433 except Exception, err: 00434 retValue['success']=False 00435 retValue['error_msgs']=retValue['error_msgs']\ 00436 +"\nError: Unable to subtract continuum with a fit order="+str(order)\ 00437 +"\n\t REULTS: "+str(results) 00438 else: 00439 if os.path.isdir(contfile) and os.path.isdir(linefile) and results: 00440 retValue = self.cmp_images(linefile, oldlinefile, 00441 "Order " + str(order) + " line image", 00442 retValue) 00443 retValue = self.cmp_images(contfile, oldcontfile, 00444 "Order " + str(order) + " continuum image", 00445 retValue) 00446 else: 00447 retValue['success']=False 00448 retValue['error_msgs']=retValue['error_msgs']\ 00449 +"\nError: output files were NOT created for fitorder="\ 00450 +str(order)+" test." 00451 00452 self.assertTrue(retValue['success'],retValue['error_msgs']) 00453 00454 def cmp_images(self, newimg, oldimg, errmsg, retval, tol=1.0e-8): 00455 """ 00456 Check that newimg matches oldimg to within tol. 00457 errmsg is a descriptive label in case there is an error. 00458 retval is updated with the results and returned. 00459 """ 00460 try: 00461 subtract_expr = '(\"' + newimg + '\"-\"' + oldimg + '\")' 00462 output_image = newimg + '.diff' 00463 immath(mode='evalexpr', expr=subtract_expr, outfile=output_image) 00464 ia.open(output_image) 00465 stats = ia.statistics() 00466 ia.close() 00467 absmax = max(abs(stats['min']), abs(stats['max'])) 00468 # in an infinite precision utopia, the difference image would be 0, but 00469 # alas, we do not live in such a world yet. 00470 if (absmax > tol): 00471 retval['success'] = False 00472 retval['error_msgs'] += errmsg + ' error: Max residual is ' + str(absmax) 00473 except Exception, err: 00474 retval['success'] = False 00475 retval['error_msgs'] += errmsg + " error: Exception thrown: " + str(err) 00476 return retval 00477 00478 00479 def test_box_and_chans(self): 00480 '''Imcontsub: Testing box and chans''' 00481 retValue = {'success': True, 'msgs': "", 'error_msgs': '' } 00482 #casalog.post("Starting imcontsub box and chans tests.", 'NORMAL2') 00483 00484 oldcfil = 'boxychans_cont.im' 00485 cfil = 'test_' + oldcfil 00486 oldlfil = 'boxychans_line.im' 00487 lfil = 'test_' + oldlfil 00488 bx = [400, 420, 490, 470] 00489 00490 try: 00491 results = imcontsub('g192_a2.image', fitorder=0, contfile=cfil, 00492 linefile=lfil, box=bx, 00493 chans='32~37') # Purposely one-sided. 00494 except Exception, err: 00495 retValue['success']=False 00496 retValue['error_msgs'] += "\nError: Unable to subtract continuum with box and chans "\ 00497 +"\n\t RESULTS: "+str(results) 00498 else: 00499 if os.path.isdir(cfil) and os.path.isdir(lfil) and results: 00500 retValue = self.cmp_images(lfil, oldlfil, 00501 "box and chans line image", retValue) 00502 retValue = self.cmp_images(cfil, oldcfil, 00503 "box and chans continuum image", 00504 retValue) 00505 else: 00506 retValue['success']=False 00507 retValue['error_msgs'] += "\nError: box and chans output files were NOT created." 00508 00509 self.assertTrue(retValue['success'],retValue['error_msgs']) 00510 00511 def suite(): 00512 return [imcontsub_test] 00513