-
Notifications
You must be signed in to change notification settings - Fork 32
/
crnx2rnx.py
116 lines (99 loc) · 3.98 KB
/
crnx2rnx.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
# coding=utf-8
"""Convert GSI Compact RINEX into Standard RINEX,
using concurent.futures.
The convert function rely on RNXCMP software. Check if you have
installed RNXCMP by typing `crx2rnx -h` in cmd.
:author: Jon Jiang
:email: jiangyingming@live.com
"""
from concurrent import futures
from textwrap import shorten
import argparse
import glob
import itertools
import os
import subprocess
import sys
import tqdm
MAX_THREADING = min(4, os.cpu_count())
def crx2rnx(src_file, out_dir, keep):
"""Convert compact RINEX file to standard RINEX."""
filename = os.path.basename(src_file)
# check if source file is already rinex file
if filename.lower().endswith('rnx') or filename.lower().endswith('o'):
return
if filename.lower().endswith('crx'):
dst_file = os.path.join(out_dir, filename[0:-3]+'rnx')
else:
dst_file = os.path.join(out_dir, filename[0:-1]+'o')
# run crx2rnx, redirect standard RINEX stdout into destination file
# and ignore the stderr.
args = 'crx2rnx', '-', src_file
with open(dst_file, 'w') as dst_writer:
status = subprocess.call(
args, stdout=dst_writer, stderr=subprocess.DEVNULL)
# check exit status of crx2rnx: {0: success, 1: error, 2: warning}
if status == 1:
# if run crx2rnx failed, remove dest file and return filename
os.remove(dst_file)
return filename
# remove source file if keep is False when successful
if not keep:
os.remove(src_file)
return
def parallel_run(function, argvs):
"""Parallel run function using argvs, display a process bar."""
# check platform, use ASCII process bar in Windows
use_ascii = True if sys.getwindowsversion().major < 10 else False
with futures.ThreadPoolExecutor(max_workers=MAX_THREADING) as executor:
todo_list = [executor.submit(function, *argv) for argv in argvs]
task_iter = futures.as_completed(todo_list)
failed_files = []
for future in tqdm.tqdm(
task_iter, total=len(todo_list), ascii=use_ascii, unit='file'):
# return None means task is success
res = future.result()
if res:
failed_files.append(res)
return failed_files
def init_args():
"""Initilize function, parse user input"""
# initilize a argument parser
parser = argparse.ArgumentParser(
description='Convert GSI Compact RINEX into Standard RINEX.'
)
# add arguments
parser.add_argument('-v', '--version', action='version',
version='%(prog)s 0.2.3')
parser.add_argument('-k', '--keep', action='store_true',
help='keep original file')
parser.add_argument('-r', '--recursive', action='store_true',
help='search file recursively')
parser.add_argument('-out', metavar='<directory>', default='rinex',
help='output directory [default: rinex in current]')
parser.add_argument('files', metavar='<file>', nargs='+',
help='file will be processed')
return parser.parse_args()
def main():
"""Main function."""
args = init_args()
globstrs, out_dir = args.files, args.out
keep_src, recursive = args.keep, args.recursive
# create output directory
os.makedirs(out_dir, exist_ok=True)
# collect input globstrs into a glob list
globs = [glob.iglob(globstr, recursive=recursive) for globstr in globstrs]
# make input args for crx2rnx function
conv_args = ((src, out_dir, keep_src) for src in itertools.chain(*globs))
print('Start processing: {}'.format(shorten(', '.join(globstrs), 62)))
if not keep_src:
print('Delete source files when complete')
# start parallel task, get a file name list of convert failed.
failed = parallel_run(crx2rnx, conv_args)
if failed:
print('\nConvert failed filename: {}'.format(', '.join(failed)))
else:
print('\nAll convert tasks are finished!')
if __name__ == '__main__':
main()