Coverage for /wheeldirectory/casa-6.7.0-12-py3.10.el8/lib/py/lib/python3.10/site-packages/casatasks/private/sdutil.py: 17%
527 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 17:39 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 17:39 +0000
1import abc
2import contextlib
3import functools
4import inspect
5import os
6import re
7import sys
8import traceback
9from types import CodeType
11import numpy
13from casatasks import casalog
14from casatools import calibrater, imager, measures
15from casatools import ms as mstool
16from casatools import mstransformer, table
18from . import flaghelper as fh
19from casatasks.private.mstools import write_history
20from casatasks.private.parallel.parallel_data_helper import ParallelDataHelper
21from casatasks.private.update_spw import update_spwchan
23class Casalog:
24 """Easily and consistently log CASA messages.
26 Motivation:
27 The origin of a message posted directly with casalog.post
28 must be specified at each casalog.post call.
30 Usage Example:
31 def my_funtion():
32 logger = Casalog(origin="my_function")
33 logger.post("Hello 1") # Logs <TaskName>::my_function::<ProcessorName> Hello 1
34 logger.post("Hello 2") # Logs <TaskName>::my_function::<ProcessorName> Hello 2
36 """
37 def __init__(self, origin: str):
38 """Construct an object posting messages having the given origin
39 """
40 self.post = functools.partial(casalog.post, origin=origin)
43@contextlib.contextmanager
44def tool_manager(vis, ctor, *args, **kwargs):
45 # this is the only syntax allowed in CASA6, code in CASA6 should be converted to
46 # call this method with a tool constructor directly
47 tool = ctor()
48 if vis and "open" in dir(tool):
49 tool.open(vis, *args, **kwargs)
50 try:
51 yield tool
52 finally:
53 if "close" in dir(tool):
54 tool.close()
55 elif "done" in dir(tool):
56 tool.done()
59def table_manager(vis, *args, **kwargs):
60 return tool_manager(vis, table, *args, **kwargs)
63def calibrater_manager(vis, *args, **kwargs):
64 return tool_manager(vis, calibrater, *args, **kwargs)
67def measures_manager(*args, **kwargs):
68 return tool_manager(None, measures, *args, **kwargs)
71def mstransformer_manager(*args, **kwargs):
72 return tool_manager(None, mstransformer, *args, **kwargs)
75def mstool_manager(vis, *args, **kwargs):
76 return tool_manager(vis, mstool, *args, **kwargs)
79def is_ms(filename):
80 if (os.path.isdir(filename)
81 and os.path.exists(filename + '/table.info')
82 and os.path.exists(filename + '/table.dat')):
83 f = open(filename + '/table.info',encoding=sys.getdefaultencoding( ))
84 lines = f.readline()
85 f.close()
86 if (lines.find('Measurement Set') != -1):
87 return True
88 else:
89 return False
90 else:
91 return False
94@contextlib.contextmanager
95def table_selector(table, taql, *args, **kwargs):
96 with table_manager(table, *args, **kwargs) as tb:
97 tsel = tb.query(taql)
98 try:
99 yield tsel
100 finally:
101 tsel.close()
104def sdtask_decorator(func):
105 """This is a decorator function for sd tasks.
107 Currently the decorator does:
109 1) set origin to the logger
110 2) handle exception
112 So, you don't need to set origin in the task any more.
113 Also, you don't need to write anything about error
114 handling in the task. If you have something to do
115 at the end of the task execution, those should be written
116 in finally block in the task class.
117 """
118 @functools.wraps(func)
119 def wrapper(*args, **kwargs):
120 # set origin
121 casalog.origin(func.__name__)
123 retval = None
124 # Any errors are handled outside the task.
125 # however, the implementation below is effectively
126 # equivalent to handling it inside the task.
127 try:
128 # execute task
129 retval = func(*args, **kwargs)
130 except Exception as e:
131 traceback_info = __format_trace(traceback.format_exc())
132 casalog.post(traceback_info, 'SEVERE')
133 casalog.post(str(e), 'ERROR')
134 raise
135 return retval
136 return wrapper
139def callable_sdtask_decorator(func):
140 """This is a decorator function for sd tasks.
142 Currently the decorator does:
144 1) set the origin of messages logged by the "sub" tasks called by the "super" task to "super"
145 For example:
146 super_casatask::casa "Msg from super task"
147 super_casatask::casa "Msg from sub-task1 called by super task"
148 super_casatask::casa "Msg from sub-task1 called by super task"
149 2) handle exception
151 So, you don't need to set origin in the task any more.
152 Also, you don't need to write anything about error handling
153 in the task. If you have something to do at the end of
154 the task execution, those should be written in finally block
155 in the task class.
157 Usage:
159 @callable_sdtask_decorator
160 def sometask(..)
161 pass
163 def othertask(..)
164 sometask(*args, **kwargs) # logged "othertask::..."
165 """
166 @functools.wraps(func)
167 def wrapper(*args, **kwargs):
168 __set_origin(inspect.stack(), casalog.getOrigin(), func.__name__)
170 retval = None
171 # Any errors are handled outside the task.
172 # however, the implementation below is effectively
173 # equivalent to handling it inside the task.
174 try:
175 # execute task
176 retval = func(*args, **kwargs)
177 except Exception as e:
178 traceback_info = __format_trace(traceback.format_exc())
179 casalog.post(traceback_info, 'SEVERE')
180 casalog.post(str(e), 'ERROR')
181 raise
182 return retval
183 return wrapper
186def __set_origin(callstack, origin, funcname):
187 for frame_info in callstack:
188 if frame_info.function == origin:
189 casalog.origin(origin)
190 return
191 casalog.origin(funcname)
194def __format_trace(s):
195 wexists = True
196 regex = r'.*sdutil\.py.*in wrapper.*'
197 retval = s
198 while wexists:
199 ss = retval.split('\n')
200 wexists = False
201 for i in range(len(ss)):
202 if re.match(regex, ss[i]):
203 ss = ss[:i] + ss[i + 2:]
204 wexists = True
205 break
206 retval = '\n'.join(ss)
207 return retval
210class sdtask_manager(object):
211 def __init__(self, cls, args):
212 self.cls = cls
213 self.args = args
215 def __enter__(self):
216 self.obj = self.cls(**self.args)
217 return self.obj
219 def __exit__(self, exc_type, exc_value, traceback):
220 # explicitly call destructure to make sure it is called here
221 self.obj.__del__()
222 del self.obj
223 if exc_type:
224 return False
225 else:
226 return True
229class sdtask_interface(object):
230 """The sdtask_interface defines a common interface for sdtask_worker class.
232 All worker classes can be used as follows:
234 worker = sdtask_worker(**locals())
235 worker.initialize()
236 worker.execute()
237 worker.finalize()
238 del worker
240 Derived classes must implement the above three methods: initialize(),
241 execute(), and finalize().
242 """
244 __metaclass__ = abc.ABCMeta
246 def __init__(self, **kwargs):
247 for (k, v) in kwargs.items():
248 setattr(self, k, v)
249 # special treatment for selection parameters
250 select_params = ['scan', 'pol', 'beam']
251 for param in select_params:
252 if hasattr(self, param):
253 setattr(self, param + 'no', getattr(self, param))
254 # casalog.post(
255 # "renaming self.%s -> self.%sno='%s'" % (param, param, getattr(self, param)))
256 delattr(self, param)
258 def __del__(self):
259 pass
261 def __enter__(self):
262 return self
264 def __exit__(self, exc_type, exc_val, exc_tb):
265 # explicitly call destructor to make sure it is called here
266 self.__del__()
267 if exc_type:
268 return False
269 else:
270 return True
272 @abc.abstractmethod
273 def initialize(self):
274 raise NotImplementedError('initialize is abstract method')
276 @abc.abstractmethod
277 def execute(self):
278 raise NotImplementedError('execute is abstract method')
280 @abc.abstractmethod
281 def finalize(self):
282 raise NotImplementedError('finalize is abstract method')
285class sdtask_template_imaging(sdtask_interface):
286 """Template class for imaging tasks.
288 The sdtask_template_imaging is a template class for worker
289 class of imaging related sdtasks. It partially implement initialize()
290 and finalize() using internal methods that must be implemented
291 in the derived classes. For initialize(), derived classes
292 must implement compile(), which sets up imaging parameters.
293 You can implement paramter_check() to do any task specific parameter
294 check in initialize().
295 For finalize(), derived classes can implement cleanup().
296 """
298 def __init__(self, **kwargs):
299 super(sdtask_template_imaging, self).__init__(**kwargs)
300 self.is_table_opened = False
301 self.is_imager_opened = False
302 self.table = table()
303 self.imager = imager()
304 # workaround for sdtpimaging
305 if not hasattr(self, 'infiles') and hasattr(self, 'infile'):
306 self.infiles = [self.infile]
308 self.__set_infiles()
309 self.__set_subtable_name()
311 def __del__(self, base=sdtask_interface):
312 # table and imager must be closed when the instance
313 # is deleted
314 self.close_table()
315 self.close_imager()
316 self.cleanup()
317 super(sdtask_template_imaging, self).__del__()
319 def open_table(self, name, nomodify=True):
320 if self.is_table_opened:
321 casalog.post('Close table before re-open', priority='WARN')
322 return
323 self.table.open(name, nomodify=nomodify)
324 self.is_table_opened = True
326 def close_table(self):
327 if self.is_table_opened:
328 self.table.close()
329 self.is_table_opened = False
331 def open_imager(self, name=''):
332 if self.is_imager_opened:
333 casalog.post('Close imager before re-open', priority='WARN')
334 return
335 self.imager.open(name)
336 self.is_imager_opened = True
338 def close_imager(self):
339 if self.is_imager_opened:
340 self.imager.close()
341 self.is_imager_opened = False
343 def initialize(self):
344 # infiles must be MS
345 for idx in range(len(self.infiles)):
346 if not is_ms(self.infiles[idx]):
347 msg = 'input data sets must be in MS format'
348 raise Exception(msg)
350 self.parameter_check()
351 self.compile()
353 def finalize(self):
354 pass
356 def parameter_check(self):
357 pass
359 def compile(self):
360 pass
362 def cleanup(self):
363 pass
365 def __set_subtable_name(self):
366 self.open_table(self.infiles[0])
367 keys = self.table.getkeywords()
368 self.close_table()
369 self.field_table = get_subtable_name(keys['FIELD'])
370 self.spw_table = get_subtable_name(keys['SPECTRAL_WINDOW'])
371 self.source_table = get_subtable_name(keys['SOURCE'])
372 self.antenna_table = get_subtable_name(keys['ANTENNA'])
373 self.polarization_table = get_subtable_name(keys['POLARIZATION'])
374 self.observation_table = get_subtable_name(keys['OBSERVATION'])
375 self.pointing_table = get_subtable_name(keys['POINTING'])
376 self.data_desc_table = get_subtable_name(keys['DATA_DESCRIPTION'])
377 self.pointing_table = get_subtable_name(keys['POINTING'])
379 def __set_infiles(self):
380 if type(self.infiles) == str:
381 self.infiles = [self.infiles]
384def __get_abspath(filename):
385 return os.path.abspath(__expand_path(filename))
388def __expand_path(filename):
389 return os.path.expanduser(os.path.expandvars(filename))
392def assert_outfile_canoverwrite_or_nonexistent(outfile=None, outform=None, overwrite=None):
393 if not overwrite and (outform.upper() != "ASCII"):
394 filename = __get_abspath(outfile)
395 if os.path.exists(filename):
396 mesg = "Output file '%s' exists." % (outfile)
397 raise Exception(mesg)
400def convert_antenna_spec_autocorr(antenna):
401 """Convert antenna (baseline) specification(s) to include autocorr data.
403 Args:
404 antenna (str): antenna specification
406 Returns:
407 str: tweaked antenna specification
408 """
409 if len(antenna) == 0:
410 return antenna
411 elif antenna.find(';') >= 0:
412 # antenna selection is semi-colon separated list of baseline
413 # specifications: 'SEL1;SEL2...'
414 return ';'.join(map(convert_antenna_spec_autocorr, antenna.split(';')))
415 elif antenna.find('&') < 0:
416 # no '&' in the selection string
417 # -> 'ANT&&&'
418 return antenna + '&&&'
419 elif antenna.endswith('&&'):
420 # 'ANT&&' or 'ANT&&&'
421 # -> as is
422 return antenna
423 elif antenna.endswith('&'):
424 # 'ANT&'
425 # -> 'ANT&&&'
426 return antenna.strip('&') + '&&&'
427 else:
428 # 'ANT1&ANT2' or 'ANT1&&ANT2'
429 # -> 'ANT1&&&;ANT2&&&'
430 specs = [a for a in antenna.split('&') if len(a) > 0]
431 return ';'.join(map(convert_antenna_spec_autocorr, specs))
434def get_antenna_selection_include_autocorr(msname, antenna):
435 """Get antenna selection string that includes autocorr data.
437 Args:
438 msname (str): name of MS
439 antenna (str): antenna selection string
441 Raises:
442 RuntimeError: failed to handle antenna selection string
444 Returns:
445 str: antenna selection string including autocorr data
446 """
447 if len(antenna) == 0:
448 # if no selection is specified, do nothing
449 return antenna
451 # test if given antenna selection is valid and if contains any autocorr data
452 ms = mstool()
453 sel = ms.msseltoindex(msname, baseline=antenna)
454 if any([b[0] == b[1] for b in sel['baselines']]):
455 antenna_autocorr = antenna
456 else:
457 antenna_autocorr = convert_antenna_spec_autocorr(antenna)
458 casalog.post(
459 'Tweaked antenna selection to include autocorr data: original "{}" tweaked "{}"'.format(
460 antenna, antenna_autocorr
461 )
462 )
463 # test if tweaked selection is valid
464 sel = ms.msseltoindex(msname, baseline=antenna_autocorr)
465 if all([b[0] != b[1] for b in sel['baselines']]):
466 raise RuntimeError('Cannot handle antenna selection properly. Abort.')
467 return antenna_autocorr
470def get_nx_ny(n):
471 nl = to_list(n, int)
472 if not nl: # check for numpy int types
473 nl = to_list(n, numpy.integer)
474 if len(nl) == 1:
475 nx = ny = nl[0]
476 else:
477 nx = nl[0]
478 ny = nl[1]
479 return (nx, ny)
482def get_cellx_celly(c, unit='arcsec'):
483 if isinstance(c, str):
484 cellx = celly = c
485 elif type(c) in (list, tuple, numpy.ndarray):
486 if len(c) == 1:
487 cellx = celly = __to_quantity_string(c[0], unit)
488 elif len(c) > 1:
489 cellx = __to_quantity_string(c[0], unit)
490 celly = __to_quantity_string(c[1], unit)
491 else:
492 cellx = celly = ''
493 else:
494 cellx = celly = __to_quantity_string(c, unit)
495 return (cellx, celly)
498def __to_quantity_string(v, unit='arcsec'):
499 if isinstance(v, str):
500 return v
501 else:
502 return '%s%s' % (v, unit)
505def get_subtable_name(v):
506 return v.replace('Table:', '').strip()
509def get_spwids(selection, infile=None):
510 # return a comma-separated string of spw IDs.
511 # selection should be an output of ms.msseltoindex()
513 spw_list = selection['spw']
514 if len(spw_list) == 0:
515 if infile is None:
516 raise Exception("infile is needed when selection['spw'] is empty.")
517 with table_manager(os.path.join(infile, 'DATA_DESCRIPTION')) as tb:
518 spw_list = tb.getcol('SPECTRAL_WINDOW_ID')
520 items = []
521 for item in spw_list:
522 items.append(str(item))
523 return ','.join(items)
526def __is_sequence_or_number(param, ptype=int):
527 """Return true if input is an array type or a number with a give data type.
529 Arguments
530 param : an array or number to test
531 ptype : the data type that param should be.
532 """
533 if hasattr(param, '__iter__'):
534 out = True
535 for p in param:
536 out &= isinstance(p, ptype)
537 return out
538 else:
539 return isinstance(param, ptype)
542def to_list(param, ptype=int, convert=False):
543 """Convert a number, an array type or a string to a list.
545 The function returns None if input values are not ptype and convert=False.
546 When convert is True, force converting input values to a list of ptype.
547 """
548 if isinstance(param, ptype): # a string or a number
549 if ptype is str:
550 return param.split()
551 elif convert:
552 return [ptype(param)]
553 else:
554 return [param]
555 if __is_sequence_or_number(param, ptype):
556 return list(param)
557 elif convert:
558 return [ptype(p) for p in param]
559 return None
562def do_mst(
563 infile,
564 datacolumn,
565 field,
566 spw,
567 timerange,
568 scan,
569 antenna,
570 timebin,
571 timespan,
572 outfile,
573 intent,
574 caller: CodeType,
575 ext_config):
576 """Call mstransform by the provided procedure.
578 Followings are parameters of mstransform, but not used by sdtimeaverage,
579 just only putting default values.
580 """
581 vis = infile # needed for ParallelDataHelper
582 outputvis = outfile # needed for ParallelDataHelper
583 separationaxis = "auto"
584 tileshape = [0]
586# intent = ''
587 correlation = ''
588 array = ''
589 uvrange = ''
590 observation = ''
591 feed = ''
593 realmodelcol = False
594 usewtspectrum = False
595 chanbin = 1
596 mode = 'channel'
597 start = 0
598 width = 1
600 maxuvwdistance = 0.0
602 ddistart = -1
603 reindex = True
604 _disableparallel = False
605 _monolithic_processing = False
607 taqlstr = ''
608 if ext_config.get('keepflags'):
609 taqlstr = "NOT (FLAG_ROW OR ALL(FLAG))"
611 # Initialize the helper class
612 pdh = ParallelDataHelper(caller.co_name, locals())
614 # When dealing with MMS, process in parallel or sequential
615 # _disableparallel is a hidden parameter. Only for debugging purposes!
616 if _disableparallel:
617 pdh.bypassParallelProcessing(1)
618 else:
619 pdh.bypassParallelProcessing(0)
621 # Validate input and output parameters
622 pdh.setupIO()
624 # Process the input Multi-MS
625 if ParallelDataHelper.isMMSAndNotServer(infile) and not _monolithic_processing:
626 do_createmms, separationaxis, do_return = __process_input_multi_ms(pdh, separationaxis)
627 if do_return:
628 return
629 # Create an output Multi-MS
630 if do_createmms:
631 __create_output_multi_ms(pdh, separationaxis)
632 return
634 # Create a local copy of the MSTransform tool
635 with mstransformer_manager() as mtlocal:
636 # Gather all the parameters in a dictionary.
637 config = {}
639 # set config param.
640 config = pdh.setupParameters(
641 inputms=infile,
642 outputms=outfile,
643 field=field,
644 spw=spw,
645 array=array,
646 scan=scan,
647 antenna=antenna,
648 correlation=correlation,
649 uvrange=uvrange,
650 timerange=timerange,
651 intent=intent,
652 observation=str(observation),
653 feed=feed,
654 taql=taqlstr)
656 # ddistart will be used in the tool when re-indexing the spw table
657 config['ddistart'] = ddistart
659 # re-index parameter is used by the pipeline to not re-index any
660 # sub-table and the associated IDs
661 config['reindex'] = reindex
663 config['datacolumn'] = datacolumn
664 dc = datacolumn.upper()
665 # Make real a virtual MODEL column in the output MS
666 if 'MODEL' in dc or dc == 'ALL':
667 config['realmodelcol'] = realmodelcol
669 config['usewtspectrum'] = usewtspectrum
671 if ext_config.get('do_check_tileshape'):
672 __check_tileshape(tileshape)
674 config['tileshape'] = tileshape
676 # set config for Averaging
677 if ext_config.get('do_timeaverage'):
678 casalog.post('Parse time averaging parameters')
679 config['timeaverage'] = True
680 config['timebin'] = timebin
681 config['timespan'] = timespan
682 config['maxuvwdistance'] = maxuvwdistance
684 # porting from sdpolaverage
685 __if_do_polaverage(config, ext_config)
687 # porting from sdpolaverage, but not used
688 if ext_config.get('parse_chanaverage'):
689 chanbin = __if_parse_chanaverage(chanbin, config, pdh)
691 # porting from sdpolaverage, but not used
692 __if_do_hanning(config, ext_config)
694 # porting from sdpolaverage, but not used
695 __if_parse_regridding_parameters(config, ext_config, mode, pdh)
697 # Configure the tool and all the parameters
698 casalog.post('%s' % config, 'DEBUG')
699 mtlocal.config(config)
701 # Open the MS, select the data and configure the output
702 mtlocal.open()
704 # Run the tool
705 casalog.post('Apply the transformations')
706 mtlocal.run()
708 """
709 CAS-12721:
710 Note: Following section were written concerning with CAS-7751 or others.
711 Program logic is copied and used without change.
712 """
713 # Update the FLAG_CMD sub-table to reflect any spw/channels selection
714 # If the spw selection is by name or FLAG_CMD contains spw with names,
715 # skip the updating
717 if (spw != '' and spw != '*') or ext_config.get('parse_chanaverage'):
718 __update_flag_cmd(infile, outfile, chanbin, spw)
720 # END
723def add_history(
724 caller,
725 casalog,
726 outfile):
727 """Write history to output MS, not the input ms."""
728 mslocal = mstool()
729 try:
730 param_names = caller.co_varnames[:caller.co_argcount]
731 local_vals = locals()
732 param_vals = [local_vals.get(p, None) for p in param_names]
733 write_history(mslocal, outfile, 'sdtimeaverage', param_names,
734 param_vals, casalog)
735 except Exception as instance:
736 casalog.post("*** Error \'%s\' updating HISTORY" % (instance),
737 'WARN')
738 return False
740 mslocal = None
742 return True
745def __if_parse_regridding_parameters(config, ext_config, mode, pdh):
746 if ext_config.get('regridms'):
747 nchan = -1
748 nspw = 1
749 interpolation = "linear"
750 restfreq = ""
751 outframe = ""
752 phasecenter = ""
753 veltype = "radio"
754 preaverage = False
755 casalog.post('Parse regridding parameters')
756 config['regridms'] = True
757 # Reset the defaults depending on the mode
758 # Only add non-empty string parameters to config dictionary
759 start, width = pdh.defaultRegridParams()
760 config['mode'] = mode
761 config['nchan'] = nchan
762 if start != '':
763 config['start'] = start
764 if width != '':
765 config['width'] = width
766 if nspw > 1:
767 casalog.post('Separate MS into %s spws' % nspw)
768 config['nspw'] = nspw
769 config['interpolation'] = interpolation
770 if restfreq != '':
771 config['restfreq'] = restfreq
772 if outframe != '':
773 config['outframe'] = outframe
774 if phasecenter != '':
775 config['phasecenter'] = phasecenter
776 config['veltype'] = veltype
777 config['preaverage'] = preaverage
780def __if_do_hanning(config, ext_config):
781 if ext_config.get('hanning'):
782 casalog.post('Apply Hanning smoothing')
783 config['hanning'] = True
786def __if_do_polaverage(config, ext_config):
787 if ext_config.get('polaverage'):
788 polaverage_ = ext_config.get('polaverage').strip()
789 if polaverage_ != '':
790 config['polaverage'] = True
791 config['polaveragemode'] = polaverage_
794def __if_parse_chanaverage(chanbin, config, pdh):
795 # Only parse chanaverage if chanbin is valid
796 if isinstance(chanbin, int) and chanbin <= 1:
797 raise ValueError('Parameter chanbin must be > 1 to do channel averaging')
799 # Validate the case of int or list chanbin
800 if pdh.validateChanBin():
801 casalog.post('Parse channel averaging parameters')
802 config['chanaverage'] = True
804 # convert numpy types, until CAS-6493 is not fixed
805 chanbin = fh.evaluateNumpyType(chanbin)
806 config['chanbin'] = chanbin
807 return chanbin
810def __update_flag_cmd(infile, outfile, chanbin, spw):
811 with table_manager(outfile + '/FLAG_CMD', nomodify=False) as mytb:
812 mslocal = mstool()
813 nflgcmds = mytb.nrows()
815 if nflgcmds > 0:
816 update_flag_cmd = False
818 # If spw selection is by name in FLAG_CMD, do not update, CAS-7751
819 mycmd = mytb.getcell('COMMAND', 0)
820 cmdlist = mycmd.split()
821 for cmd in cmdlist:
822 # Match only spw indices, not names
823 if cmd.__contains__('spw'):
824 cmd = cmd.strip('spw=')
825 spwstr = re.search('^[^a-zA-Z]+$', cmd)
826 if spwstr is not None and spwstr.string.__len__() > 0:
827 update_flag_cmd = True
828 break
830 if update_flag_cmd:
831 mademod = False
832 cmds = mytb.getcol('COMMAND')
833 widths = {}
834 if hasattr(chanbin, 'has_key'):
835 widths = chanbin
836 else:
837 if hasattr(chanbin, '__iter__') and len(chanbin) > 1:
838 for i in range(len(chanbin)):
839 widths[i] = chanbin[i]
840 elif chanbin != 1:
841 numspw = len(mslocal.msseltoindex(vis=infile,
842 spw='*')['spw'])
843 if hasattr(chanbin, '__iter__'):
844 w = chanbin[0]
845 else:
846 w = chanbin
847 for i in range(numspw):
848 widths[i] = w
849 for rownum in range(nflgcmds):
850 # Matches a bare number or a string quoted any way.
851 spwmatch = re.search(r'spw\s*=\s*(\S+)', cmds[rownum])
852 if spwmatch:
853 sch1 = spwmatch.groups()[0]
854 sch1 = re.sub(r"[\'\"]", '', sch1) # Dequote
855 # Provide a default in case the split selection excludes
856 # cmds[rownum]. update_spwchan() will throw an exception
857 # in that case.
858 cmd = ''
859 try:
860 sch2 = update_spwchan(
861 infile, spw, sch1, truncate=True, widths=widths)
862 if sch2:
863 repl = ''
864 if sch2 != '*':
865 repl = "spw='" + sch2 + "'"
866 cmd = cmds[rownum].replace(
867 spwmatch.group(), repl)
868 # except: # cmd[rownum] no longer applies.
869 except Exception as e:
870 casalog.post(
871 'Error %s updating row %d of FLAG_CMD' %
872 (e, rownum), 'WARN')
873 casalog.post('sch1 = ' + sch1, 'DEBUG1')
874 casalog.post('cmd = ' + cmd, 'DEBUG1')
875 if cmd != cmds[rownum]:
876 mademod = True
877 cmds[rownum] = cmd
878 if mademod:
879 casalog.post('Updating FLAG_CMD', 'INFO')
880 mytb.putcol('COMMAND', cmds)
882 else:
883 casalog.post(
884 'FLAG_CMD table contains spw selection by name. Will not update it!', 'DEBUG')
887def __check_tileshape(tileshape):
888 # Add the tile shape parameter
889 if tileshape.__len__() == 1:
890 # The only allowed values are 0 or 1
891 if tileshape[0] != 0 and tileshape[0] != 1:
892 raise ValueError('When tileshape has one element, it should be either 0 or 1.')
894 elif tileshape.__len__() != 3:
895 # The 3 elements are: correlations, channels, rows
896 raise ValueError('Parameter tileshape must have 1 or 3 elements.')
899def __process_input_multi_ms(pdh, separationaxis):
900 """Process MS.
902 retval{'status': True, 'axis':''} --> can run in parallel
903 retval{'status': False, 'axis':'value'} --> treat MMS as monolithic MS,
904 set new axis for output MMS
905 retval{'status': False, 'axis':''} --> treat MMS as monolithic MS,
906 create an output MS
907 """
908 retval = pdh.validateInputParams()
910 # Cannot create an output MMS.
911 if not retval['status'] and retval['axis'] == '':
912 casalog.post('Cannot process MMS with the requested transformations', 'WARN')
913 casalog.post('Use task listpartition to see the contents of the MMS')
914 casalog.post('Will create an output MS', 'WARN')
915 createmms = False
916 return createmms, separationaxis, False
918 # MMS is processed as monolithic MS.
919 elif not retval['status'] and retval['axis'] != '':
920 createmms = True
921 pdh.override__args('createmms', True)
922 pdh.override__args('monolithic_processing', True)
923 separationaxis = retval['axis']
924 pdh.override__args('separationaxis', retval['axis'])
925 casalog.post("Will process the input MMS as a monolithic MS", 'WARN')
926 casalog.post(
927 f"Will create an output MMS with separation axis \'{retval['axis']}\'",
928 priority='WARN')
929 return createmms, separationaxis, False
931 # MMS is processed in parallel
932 else:
933 createmms = False
934 pdh.override__args('createmms', False)
935 pdh.setupCluster('sdpolaverage')
936 pdh.go()
937 return createmms, separationaxis, True
940def __create_output_multi_ms(pdh, separationaxis):
941 # Check the heuristics of separationaxis and the requested transformations
942 pval = pdh.validateOutputParams()
943 if pval == 0:
944 raise RuntimeError(
945 'Cannot create MMS using separationaxis=%s with some of the requested transformations.'
946 % separationaxis
947 )
948 pdh.setupCluster('sdpolaverage')
949 pdh.go()
950 _monolithic_processing = False