##// END OF EJS Templates
Add license, update setup and changelog
Juan C. Espinoza -
r1329:16056ee07511
parent child
Show More
@@ -0,0 +1,28
1 This software, unless otherwise noted, is licensed under the BSD 3-clause.
2
3 Copyright (c) 2012-2020 Jicamarca Radio Observatory
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10
11 * Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
14
15 * Neither the name of the copyright holder nor the names of its
16 contributors may be used to endorse or promote products derived from
17 this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,114 +1,102
1 # Byte-compiled / optimized / DLL files
1 # Byte-compiled / optimized / DLL files
2 __pycache__/
2 __pycache__/
3 *.py[cod]
3 *.py[cod]
4 *$py.class
4 *$py.class
5
5
6 # C extensions
6 # C extensions
7 *.so
7 *.so
8
8
9 # Distribution / packaging
9 # Distribution / packaging
10 .Python
10 .Python
11 env/
11 env/
12 build/
12 build/
13 develop-eggs/
13 develop-eggs/
14 dist/
14 dist/
15 downloads/
15 downloads/
16 eggs/
16 eggs/
17 .eggs/
17 .eggs/
18 lib/
18 lib/
19 lib64/
19 lib64/
20 parts/
20 parts/
21 sdist/
21 sdist/
22 var/
22 var/
23 wheels/
23 wheels/
24 *.egg-info/
24 *.egg-info/
25 .installed.cfg
25 .installed.cfg
26 *.egg
26 *.egg
27
27
28 # PyInstaller
28 # PyInstaller
29 # Usually these files are written by a python script from a template
29 # Usually these files are written by a python script from a template
30 # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 *.manifest
31 *.manifest
32 *.spec
32 *.spec
33
33
34 # Installer logs
34 # Installer logs
35 pip-log.txt
35 pip-log.txt
36 pip-delete-this-directory.txt
36 pip-delete-this-directory.txt
37
37
38 # Unit test / coverage reports
38 # Unit test / coverage reports
39 htmlcov/
39 htmlcov/
40 .tox/
40 .tox/
41 .coverage
41 .coverage
42 .coverage.*
42 .coverage.*
43 .cache
43 .cache
44 nosetests.xml
44 nosetests.xml
45 coverage.xml
45 coverage.xml
46 *,cover
46 *,cover
47 .hypothesis/
47 .hypothesis/
48
48
49 # Translations
49 # Translations
50 *.mo
50 *.mo
51 *.pot
51 *.pot
52
52
53 # Django stuff:
53 # Django stuff:
54 *.log
54 *.log
55 local_settings.py
55 local_settings.py
56
56
57 # Flask stuff:
57 # Flask stuff:
58 instance/
58 instance/
59 .webassets-cache
59 .webassets-cache
60
60
61 # Scrapy stuff:
61 # Scrapy stuff:
62 .scrapy
62 .scrapy
63
63
64 # Sphinx documentation
64 # Sphinx documentation
65 docs/_build/
65 docs/_build/
66
66
67 # PyBuilder
67 # PyBuilder
68 target/
68 target/
69
69
70 # Jupyter Notebook
70 # Jupyter Notebook
71 .ipynb_checkpoints
71 .ipynb_checkpoints
72
72
73 # pyenv
73 # pyenv
74 .python-version
74 .python-version
75
75
76 # celery beat schedule file
76 # celery beat schedule file
77 celerybeat-schedule
77 celerybeat-schedule
78
78
79 # SageMath parsed files
79 # SageMath parsed files
80 *.sage.py
80 *.sage.py
81
81
82 # dotenv
82 # dotenv
83 .env
83 .env
84
84
85 # virtualenv
85 # virtualenv
86 .venv
86 .venv
87 venv/
87 venv/
88 ENV/
88 ENV/
89
89
90 # Spyder project settings
90 # Spyder project settings
91 .spyderproject
91 .spyderproject
92 .spyproject
92 .spyproject
93
93
94 # Rope project settings
94 # Rope project settings
95 .ropeproject
95 .ropeproject
96
96
97 # mkdocs documentation
97 # mkdocs documentation
98 /site
98 /site
99
99
100 # eclipse
100 # eclipse
101 .project
101 .project
102 .pydevproject
102 .pydevproject
103 # vscode
104
105 .vscode
106
107 schaingui/node_modules/
108 schainpy/scripts/
109 .svn/
110 *.png
111 *.pyc
112 .vscode
113 trash
114 *.log
@@ -1,121 +1,143
1 # CHANGELOG:
1 # CHANGELOG
2
3 ## 3.0.0
2
4
3 ## 3.0
4 * Python 3.x & 2.X compatible
5 * Python 3.x & 2.X compatible
5 * New architecture with multiprocessing support
6 * New architecture with multiprocessing support
6 * Add @MPDecorator for multiprocessing Operations (Plots, Writers and Publishers)
7 * Add @MPDecorator for multiprocessing Operations (Plots, Writers and Publishers)
7 * Added new type of operation `external` for non-locking operations
8 * Added new type of operation `external` for non-locking operations
8 * New plotting architecture with buffering/throttle capabilities to speed up plots
9 * New plotting architecture with buffering/throttle capabilities to speed up plots
9 * Clean controller to optimize scripts (format & optype are no longer required)
10 * Clean controller to optimize scripts (format & optype are no longer required)
11 * Replace ParamReader and ParamWriter with new flexible HDFReader and HDFWriter
10 * New GUI with dinamic load of Units and operations (use Kivy framework)
12 * New GUI with dinamic load of Units and operations (use Kivy framework)
13 * Clean code
11
14
12 ## 2.3
15 ## 2.3
16
13 * Added support for Madrigal formats (reading/writing).
17 * Added support for Madrigal formats (reading/writing).
14 * Added support for reading BLTR parameters (*.sswma).
18 * Added support for reading BLTR parameters (*.sswma).
15 * Added support for reading Julia format (*.dat).
19 * Added support for reading Julia format (*.dat).
16 * Added high order function `MPProject` for multiprocessing scripts.
20 * Added high order function `MPProject` for multiprocessing scripts.
17 * Added two new Processing Units `PublishData` and `ReceiverData` for receiving and sending dataOut through multiple ways (tcp, ipc, inproc).
21 * Added two new Processing Units `PublishData` and `ReceiverData` for receiving and sending dataOut through multiple ways (tcp, ipc, inproc).
18 * Added a new graphics Processing Unit `PlotterReceiver`. It is decoupled from normal processing sequence with support for data generated by multiprocessing scripts.
22 * Added a new graphics Processing Unit `PlotterReceiver`. It is decoupled from normal processing sequence with support for data generated by multiprocessing scripts.
19 * Added support for sending realtime graphic to web server.
23 * Added support for sending realtime graphic to web server.
20 * GUI command `schain` is now `schainGUI`.
24 * GUI command `schain` is now `schainGUI`.
21 * Added a CLI tool named `schain`.
25 * Added a CLI tool named `schain`.
22 * Scripts templates can be now generated with `schain generate`.
26 * Scripts templates can be now generated with `schain generate`.
23 * Now it is possible to search Processing Units and Operations with `schain search [module]` to get the right name and its allowed parameters.
27 * Now it is possible to search Processing Units and Operations with `schain search [module]` to get the right name and its allowed parameters.
24 * `schain xml` to run xml scripts.
28 * `schain xml` to run xml scripts.
25 * Added suggestions when parameters are poorly written.
29 * Added suggestions when parameters are poorly written.
26 * `Controller.start()` now runs in a different process than the process calling it.
30 * `Controller.start()` now runs in a different process than the process calling it.
27 * Added `schainpy.utils.log` for log standarization.
31 * Added `schainpy.utils.log` for log standarization.
28 * Running script on online mode no longer ignores date and hour. Issue #1109.
32 * Running script on online mode no longer ignores date and hour. Issue #1109.
29 * Added support for receving voltage data directly from JARS (tcp, ipc).
33 * Added support for receving voltage data directly from JARS (tcp, ipc).
30 * Updated README for MAC OS GUI installation.
34 * Updated README for MAC OS GUI installation.
31 * Setup now installs numpy.
35 * Setup now installs numpy.
32
36
33 ## 2.2.6
37 ## 2.2.6
38
34 * Graphics generated by the GUI are now the same as generated by scripts. Issue #1074.
39 * Graphics generated by the GUI are now the same as generated by scripts. Issue #1074.
35 * Added support for C extensions.
40 * Added support for C extensions.
36 * Function `hildebrand_sehkon` optimized with a C wrapper.
41 * Function `hildebrand_sehkon` optimized with a C wrapper.
37 * Numpy version updated.
42 * Numpy version updated.
38 * Migration to GIT.
43 * Migration to GIT.
39
44
40 ## 2.2.5:
45 ## 2.2.5:
46
41 * splitProfiles and combineProfiles modules were added to VoltageProc and Signal Chain GUI.
47 * splitProfiles and combineProfiles modules were added to VoltageProc and Signal Chain GUI.
42 * nProfiles of USRP data (hdf5) is the number of profiles thera are in one second.
48 * nProfiles of USRP data (hdf5) is the number of profiles thera are in one second.
43 * jroPlotter works directly with data objects instead of dictionaries
49 * jroPlotter works directly with data objects instead of dictionaries
44 * script "schain" was added to Signal Chain installer
50 * script "schain" was added to Signal Chain installer
45
51
46 ## 2.2.4.1:
52 ## 2.2.4.1:
53
47 * jroIO_usrp.py is update to read Sandra's data
54 * jroIO_usrp.py is update to read Sandra's data
48 * decimation in Spectra and RTI plots is always enabled.
55 * decimation in Spectra and RTI plots is always enabled.
49 * time* window option added to GUI
56 * time* window option added to GUI
50
57
51 ## 2.2.4:
58 ## 2.2.4:
59
52 * jroproc_spectra_lags.py added to schainpy
60 * jroproc_spectra_lags.py added to schainpy
53 * Bug fixed in schainGUI: ProcUnit was created with the same id in some cases.
61 * Bug fixed in schainGUI: ProcUnit was created with the same id in some cases.
54 * Bug fixed in jroHeaderIO: Header size validation.
62 * Bug fixed in jroHeaderIO: Header size validation.
55
63
56 ## 2.2.3.1:
64 ## 2.2.3.1:
65
57 * Filtering block by time has been added.
66 * Filtering block by time has been added.
58 * Bug fixed plotting RTI, CoherenceMap and others using xmin and xmax parameters. The first day worked
67 * Bug fixed plotting RTI, CoherenceMap and others using xmin and xmax parameters. The first day worked
59 properly but the next days did not.
68 properly but the next days did not.
60
69
61 ## 2.2.3:
70 ## 2.2.3:
71
62 * Bug fixed in GUI: Error getting(reading) Code value
72 * Bug fixed in GUI: Error getting(reading) Code value
63 * Bug fixed in GUI: Flip option always needs channelList field
73 * Bug fixed in GUI: Flip option always needs channelList field
64 * Bug fixed in jrodata: when one branch modified a value in "dataOut" (example: dataOut.code) this value
74 * Bug fixed in jrodata: when one branch modified a value in "dataOut" (example: dataOut.code) this value
65 was modified for every branch (because this was a reference). It was modified in data.copy()
75 was modified for every branch (because this was a reference). It was modified in data.copy()
66 * Bug fixed in jroproc_voltage.profileSelector(): rangeList replaces to profileRangeList.
76 * Bug fixed in jroproc_voltage.profileSelector(): rangeList replaces to profileRangeList.
67
77
68 ## 2.2.2:
78 ## 2.2.2:
79
69 * VoltageProc: ProfileSelector, Reshape, Decoder with nTxs!=1 and getblock=True was tested
80 * VoltageProc: ProfileSelector, Reshape, Decoder with nTxs!=1 and getblock=True was tested
70 * Rawdata and testRawdata.py added to Signal Chain project
81 * Rawdata and testRawdata.py added to Signal Chain project
71
82
72 ## 2.2.1:
83 ## 2.2.1:
84
73 * Bugs fixed in GUI
85 * Bugs fixed in GUI
74 * Views were improved in GUI
86 * Views were improved in GUI
75 * Support to MST* ISR experiments
87 * Support to MST* ISR experiments
76 * Bug fixed getting noise using hyldebrant. (minimum number of points > 20%)
88 * Bug fixed getting noise using hyldebrant. (minimum number of points > 20%)
77 * handleError added to jroplotter.py
89 * handleError added to jroplotter.py
78
90
79 ## 2.2.0:
91 ## 2.2.0:
92
80 * GUI: use of external plotter
93 * GUI: use of external plotter
81 * Compatible with matplotlib 1.5.0
94 * Compatible with matplotlib 1.5.0
82
95
83 ## 2.1.5:
96 ## 2.1.5:
97
84 * serializer module added to Signal Chain
98 * serializer module added to Signal Chain
85 * jroplotter.py added to Signal Chain
99 * jroplotter.py added to Signal Chain
86
100
87 ## 2.1.4.2:
101 ## 2.1.4.2:
102
88 * A new Plotter Class was added
103 * A new Plotter Class was added
89 * Project.start() does not accept filename as a parameter anymore
104 * Project.start() does not accept filename as a parameter anymore
90
105
91 ## 2.1.4.1:
106 ## 2.1.4.1:
107
92 * Send notifications when an error different to ValueError is detected
108 * Send notifications when an error different to ValueError is detected
93
109
94 ## 2.1.4:
110 ## 2.1.4:
111
95 * Sending error notifications to signal chain administrator
112 * Sending error notifications to signal chain administrator
96 * Login to email server added
113 * Login to email server added
97
114
98 ## 2.1.3.3:
115 ## 2.1.3.3:
116
99 * Colored Button Icons were added to GUI
117 * Colored Button Icons were added to GUI
100
118
101 ## 2.1.3.2:
119 ## 2.1.3.2:
120
102 * GUI: user interaction enhanced
121 * GUI: user interaction enhanced
103 * controller_api.py: Safe access to ControllerThead
122 * controller_api.py: Safe access to ControllerThead
104
123
105 ## 2.1.3.1:
124 ## 2.1.3.1:
125
106 * GUI: every icon were resized
126 * GUI: every icon were resized
107 * jroproc_voltage.py: Print a message when "Read from code" option is selected and the code is not defined inside data file
127 * jroproc_voltage.py: Print a message when "Read from code" option is selected and the code is not defined inside data file
108
128
109 ## 2.1.3:
129 ## 2.1.3:
130
110 * jroplot_heispectra.py: SpectraHeisScope was not showing the right channels
131 * jroplot_heispectra.py: SpectraHeisScope was not showing the right channels
111 * jroproc_voltage.py: Bug fixed selecting profiles (self.nProfiles took a wrong value),
132 * jroproc_voltage.py: Bug fixed selecting profiles (self.nProfiles took a wrong value),
112 Bug fixed selecting heights by block (selecting profiles instead heights)
133 Bug fixed selecting heights by block (selecting profiles instead heights)
113 * jroproc_voltage.py: New feature added: decoding data by block using FFT.
134 * jroproc_voltage.py: New feature added: decoding data by block using FFT.
114 * jroIO_heispectra.py: Bug fixed in FitsReader. Using local Fits instance instead schainpy.mode.data.jrodata.Fits.
135 * jroIO_heispectra.py: Bug fixed in FitsReader. Using local Fits instance instead schainpy.mode.data.jrodata.Fits.
115 * jroIO_heispectra.py: Channel index list does not exist.
136 * jroIO_heispectra.py: Channel index list does not exist.
116
137
117 ## 2.1.2:
138 ## 2.1.2:
139
118 * jroutils_ftp.py: Bug fixed, Any error sending file stopped the Server Thread
140 * jroutils_ftp.py: Bug fixed, Any error sending file stopped the Server Thread
119 Server thread opens and closes remote server each time file list is sent
141 Server thread opens and closes remote server each time file list is sent
120 * jroplot_spectra.py: Noise path was not being created when noise data is saved.
142 * jroplot_spectra.py: Noise path was not being created when noise data is saved.
121 * jroIO_base.py: startTime can be greater than endTime. Example: SpreadF [18:00 * 07:00] No newline at end of file
143 * jroIO_base.py: startTime can be greater than endTime. Example: SpreadF [18:00 * 07:00]
@@ -1,158 +1,102
1 # Signal Chain
1 # Signal Chain
2
2
3 ## Introduction
3 Signal Chain is a radar data processing library wich includes modules to read,
4 and write different files formats, besides modules to process and visualize the
5 data.
4
6
5 Signal Chain (SCh) is a radar data processing library developed using [Python](www.python.org) at JRO. SCh provides modules to read, write, process and plot data.
7 ## Dependencies
6
8
7 ## Installation
8
9 Install system dependencies, clone the latest version from [here](http://jro-dev.igp.gob.pe/rhodecode/schain/) and install it as a normal python package, we strongly recommend to use Anaconda or a virtual environment for the installation.
10
11 ### Dependencies
12 - GCC (gcc or gfortran)
9 - GCC (gcc or gfortran)
13 - Python.h (python-dev or python-devel)
10 - Python.h (python-dev or python-devel)
14 - Python-TK (python-tk)
11 - Python-TK (python-tk)
15 - HDF5 libraries (libhdf5-dev)
12 - HDF5 libraries (libhdf5-dev)
16
13
17 ### Linux based system (e.g. ubuntu)
14 ## Installation
18 ```
19 $ git clone http://jro-dev.igp.gob.pe/rhodecode/schain/
20 $ cd schain
21 $ git checkout `schain-branch` (optional)
22 $ sudo pip install ./
23 ```
24
15
25 ### MAC Os
16 To get started the easiest way to install it is through [PyPI](https://pypi.org/project/schainpy/) with pip:
26 ```
17
27 $ brew install python
18 ```bash
28 $ git clone http://jro-dev.igp.gob.pe/rhodecode/schain/
19 pip install schainpy
29 $ cd schain
30 $ git checkout `schain-branch` (optional)
31 $ sudo pip install ./
32 ```
20 ```
33
21
34 ### Docker
22 ### From source
35
23
36 Download Dockerfile from the repository, and create a docker image
24 First, ensure that you have the above-listed dependencies installed, then clone
25 the repository and install as normal python package:
37
26
27 ```bash
28 git clone https://github.com/JRO-Peru/schain.git
29 cd schain
30 git checkout `branch-name` (optional)
31 sudo pip install ./
38 ```
32 ```
39 $ docker build -t schain .
40 ```
41
33
42 You can run a container using an xml file or a schain script also you need to mount a volume for the data input and for the output files/plots
34 ### Using Docker
35
36 Download Dockerfile from the repository, and create a docker image:
37
38 ```bash
39 docker build -t schain .
43 ```
40 ```
44 $ docker run -it --rm --volume /path/to/host/data:/data schain xml /data/test.xml
41
45 $ docker run -it --rm --volume /path/to/host/data:/data --entrypoint /urs/local/bin/python schain /data/test.py
42 You can run a container using an xml file or a schain script also you need to
43 mount a volume for the data input and for the output files/plots:
44
45 ```bash
46 docker run -it --rm --volume /path/to/host/data:/data schain xml /data/test.xml
47 docker run -it --rm --volume /path/to/host/data:/data --entrypoint /urs/local/bin/python schain /data/test.py
46 ```
48 ```
47
49
48 ## CLI (command line interface)
50 ## CLI (command line interface)
49
51
50 Signal Chain provides the following commands:
52 Signal Chain provides the following commands:
51
53
52 - schainGUI: Open the GUI
54 - schainGUI: Open the GUI
53 - schain: Signal chain command line
55 - schain: Signal chain command line
54
56
57 ## Example
55
58
56 ## First Script
59 Here you can find an script to read Spectra data (.pdata), remove dc and plot
57
60 self-spectra & RTI:
58 Here you can find an script to read Spectra data (.pdata), remove dc and plot spectra & RTI
59
60 First import SCh and creating a project
61
61
62 ```python
62 ```python
63 #!/usr/bin/python
63 #!/usr/bin/python
64
64
65 from schainpy.controller import Project
65 from schainpy.controller import Project
66
66
67 prj = Project()
67 prj = Project()
68 prj.setup(
69 id = '100',
70 name='test',
71 description='Basic experiment'
72 )
73 ```
74
68
75 Add read unit and operations
76
77 ```python
78 read_unit = prj.addReadUnit(
69 read_unit = prj.addReadUnit(
79 datatype='Spectra',
70 datatype='Spectra',
80 path='/path/to/pdata/',
71 path='/path/to/pdata/',
81 startDate='2014/01/31',
72 startDate='2014/01/31',
82 endDate='2014/03/31',
73 endDate='2014/03/31',
83 startTime='00:00:00',
74 startTime='00:00:00',
84 endTime='23:59:59',
75 endTime='23:59:59',
85 online=0,
76 online=0,
86 walk=0
77 walk=0
87 )
78 )
88
79
89 proc_unit = prj.addProcUnit(datatype='Spectra', inputId=read_unit.getId())
80 proc_unit = prj.addProcUnit(
90
81 datatype='Spectra',
91 op = proc_unit.addOperation(name='selectChannels')
82 inputId=read_unit.getId()
92 op.addParameter(name='channelList', value='0,1')
83 )
93
94 op = proc_unit.addOperation(name='selectHeights')
95 op.addParameter(name='minHei', value='80')
96 op.addParameter(name='maxHei', value='200')
97
98 op = proc_unit.addOperation(name='removeDC')
99
100 ```
101
102 Plot data & start project
103
104 ```python
105 op = proc_unit.addOperation(name='SpectraPlot')
106 op.addParameter(name='id', value='1')
107 op.addParameter(name='wintitle', value='Spectra')
108
109 op = procUnitConfObj1.addOperation(name='RTIPlot')
110 op.addParameter(name='id', value='2')
111 op.addParameter(name='wintitle', value='RTI')
112
113 prj.start()
114
115 ```
116
117 Full script
118
119
120 ```python
121 #!/usr/bin/python
122
123 from schainpy.prj import Project
124
125 prj = Project()
126 prj.setup(id = '100',
127 name='test',
128 description='Basic experiment')
129 read_unit = prj.addReadUnit(datatype='Spectra',
130 path='/path/to/pdata/',
131 startDate='2014/01/31',
132 endDate='2014/03/31',
133 startTime='00:00:00',
134 endTime='23:59:59',
135 online=0,
136 walk=0)
137
138 proc_unit = prj.addProcUnit(datatype='Spectra',
139 inputId=read_unit.getId())
140
84
141 op = proc_unit.addOperation(name='selectChannels')
85 op = proc_unit.addOperation(name='selectChannels')
142 op.addParameter(name='channelList', value='0,1')
86 op.addParameter(name='channelList', value='0,1')
143
87
144 op = proc_unit.addOperation(name='selectHeights')
88 op = proc_unit.addOperation(name='selectHeights')
145 op.addParameter(name='minHei', value='80')
89 op.addParameter(name='minHei', value='80')
146 op.addParameter(name='maxHei', value='200')
90 op.addParameter(name='maxHei', value='200')
147
91
148 op = proc_unit.addOperation(name='removeDC')
92 op = proc_unit.addOperation(name='removeDC')
149
93
150 op = proc_unit.addOperation(name='SpectraPlot')
94 op = proc_unit.addOperation(name='SpectraPlot')
151 op.addParameter(name='wintitle', value='Spectra', format='str')
95 op.addParameter(name='wintitle', value='Spectra', format='str')
152
96
153 op = procUnitConfObj1.addOperation(name='RTIPlot')
97 op = procUnitConfObj1.addOperation(name='RTIPlot')
154 op.addParameter(name='wintitle', value='RTI', format='str')
98 op.addParameter(name='wintitle', value='RTI', format='str')
155
99
156 prj.start()
100 prj.start()
157
101
158 ``` No newline at end of file
102 ```
@@ -1,7 +1,5
1 '''
1 """Signal chain python package"""
2 Created on Jul 3, 2018
3
2
4 @author $Author$
3 from .controller import Project
5 @version $Id$
4
6 '''
5 __version__ = '3.0.0'
7 __version__ = '3.0'
@@ -1,648 +1,656
1 '''
1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
2 Main routines to create a Signal Chain project
2 # All rights reserved.
3 '''
3 #
4 # Distributed under the terms of the BSD 3-clause license.
5 """API to create signal chain projects
6
7 The API is provide through class: Project
8 """
4
9
5 import re
10 import re
6 import sys
11 import sys
7 import ast
12 import ast
8 import datetime
13 import datetime
9 import traceback
14 import traceback
10 import time
15 import time
11 from multiprocessing import Process, Queue
16 from multiprocessing import Process, Queue
12 from threading import Thread
17 from threading import Thread
13 from xml.etree.ElementTree import ElementTree, Element, SubElement
18 from xml.etree.ElementTree import ElementTree, Element, SubElement
14
19
15 from schainpy.admin import Alarm, SchainWarning
20 from schainpy.admin import Alarm, SchainWarning
16 from schainpy.model import *
21 from schainpy.model import *
17 from schainpy.utils import log
22 from schainpy.utils import log
18
23
19
24
20 class ConfBase():
25 class ConfBase():
21
26
22 def __init__(self):
27 def __init__(self):
23
28
24 self.id = '0'
29 self.id = '0'
25 self.name = None
30 self.name = None
26 self.priority = None
31 self.priority = None
27 self.parameters = {}
32 self.parameters = {}
28 self.object = None
33 self.object = None
29 self.operations = []
34 self.operations = []
30
35
31 def getId(self):
36 def getId(self):
32
37
33 return self.id
38 return self.id
34
39
35 def getNewId(self):
40 def getNewId(self):
36
41
37 return int(self.id) * 10 + len(self.operations) + 1
42 return int(self.id) * 10 + len(self.operations) + 1
38
43
39 def updateId(self, new_id):
44 def updateId(self, new_id):
40
45
41 self.id = str(new_id)
46 self.id = str(new_id)
42
47
43 n = 1
48 n = 1
44 for conf in self.operations:
49 for conf in self.operations:
45 conf_id = str(int(new_id) * 10 + n)
50 conf_id = str(int(new_id) * 10 + n)
46 conf.updateId(conf_id)
51 conf.updateId(conf_id)
47 n += 1
52 n += 1
48
53
49 def getKwargs(self):
54 def getKwargs(self):
50
55
51 params = {}
56 params = {}
52
57
53 for key, value in self.parameters.items():
58 for key, value in self.parameters.items():
54 if value not in (None, '', ' '):
59 if value not in (None, '', ' '):
55 params[key] = value
60 params[key] = value
56
61
57 return params
62 return params
58
63
59 def update(self, **kwargs):
64 def update(self, **kwargs):
60
65
61 for key, value in kwargs.items():
66 for key, value in kwargs.items():
62 self.addParameter(name=key, value=value)
67 self.addParameter(name=key, value=value)
63
68
64 def addParameter(self, name, value, format=None):
69 def addParameter(self, name, value, format=None):
65 '''
70 '''
66 '''
71 '''
67
72
68 if isinstance(value, str) and re.search(r'(\d+/\d+/\d+)', value):
73 if isinstance(value, str) and re.search(r'(\d+/\d+/\d+)', value):
69 self.parameters[name] = datetime.date(*[int(x) for x in value.split('/')])
74 self.parameters[name] = datetime.date(*[int(x) for x in value.split('/')])
70 elif isinstance(value, str) and re.search(r'(\d+:\d+:\d+)', value):
75 elif isinstance(value, str) and re.search(r'(\d+:\d+:\d+)', value):
71 self.parameters[name] = datetime.time(*[int(x) for x in value.split(':')])
76 self.parameters[name] = datetime.time(*[int(x) for x in value.split(':')])
72 else:
77 else:
73 try:
78 try:
74 self.parameters[name] = ast.literal_eval(value)
79 self.parameters[name] = ast.literal_eval(value)
75 except:
80 except:
76 if isinstance(value, str) and ',' in value:
81 if isinstance(value, str) and ',' in value:
77 self.parameters[name] = value.split(',')
82 self.parameters[name] = value.split(',')
78 else:
83 else:
79 self.parameters[name] = value
84 self.parameters[name] = value
80
85
81 def getParameters(self):
86 def getParameters(self):
82
87
83 params = {}
88 params = {}
84 for key, value in self.parameters.items():
89 for key, value in self.parameters.items():
85 s = type(value).__name__
90 s = type(value).__name__
86 if s == 'date':
91 if s == 'date':
87 params[key] = value.strftime('%Y/%m/%d')
92 params[key] = value.strftime('%Y/%m/%d')
88 elif s == 'time':
93 elif s == 'time':
89 params[key] = value.strftime('%H:%M:%S')
94 params[key] = value.strftime('%H:%M:%S')
90 else:
95 else:
91 params[key] = str(value)
96 params[key] = str(value)
92
97
93 return params
98 return params
94
99
95 def makeXml(self, element):
100 def makeXml(self, element):
96
101
97 xml = SubElement(element, self.ELEMENTNAME)
102 xml = SubElement(element, self.ELEMENTNAME)
98 for label in self.xml_labels:
103 for label in self.xml_labels:
99 xml.set(label, str(getattr(self, label)))
104 xml.set(label, str(getattr(self, label)))
100
105
101 for key, value in self.getParameters().items():
106 for key, value in self.getParameters().items():
102 xml_param = SubElement(xml, 'Parameter')
107 xml_param = SubElement(xml, 'Parameter')
103 xml_param.set('name', key)
108 xml_param.set('name', key)
104 xml_param.set('value', value)
109 xml_param.set('value', value)
105
110
106 for conf in self.operations:
111 for conf in self.operations:
107 conf.makeXml(xml)
112 conf.makeXml(xml)
108
113
109 def __str__(self):
114 def __str__(self):
110
115
111 if self.ELEMENTNAME == 'Operation':
116 if self.ELEMENTNAME == 'Operation':
112 s = ' {}[id={}]\n'.format(self.name, self.id)
117 s = ' {}[id={}]\n'.format(self.name, self.id)
113 else:
118 else:
114 s = '{}[id={}, inputId={}]\n'.format(self.name, self.id, self.inputId)
119 s = '{}[id={}, inputId={}]\n'.format(self.name, self.id, self.inputId)
115
120
116 for key, value in self.parameters.items():
121 for key, value in self.parameters.items():
117 if self.ELEMENTNAME == 'Operation':
122 if self.ELEMENTNAME == 'Operation':
118 s += ' {}: {}\n'.format(key, value)
123 s += ' {}: {}\n'.format(key, value)
119 else:
124 else:
120 s += ' {}: {}\n'.format(key, value)
125 s += ' {}: {}\n'.format(key, value)
121
126
122 for conf in self.operations:
127 for conf in self.operations:
123 s += str(conf)
128 s += str(conf)
124
129
125 return s
130 return s
126
131
127 class OperationConf(ConfBase):
132 class OperationConf(ConfBase):
128
133
129 ELEMENTNAME = 'Operation'
134 ELEMENTNAME = 'Operation'
130 xml_labels = ['id', 'name']
135 xml_labels = ['id', 'name']
131
136
132 def setup(self, id, name, priority, project_id, err_queue):
137 def setup(self, id, name, priority, project_id, err_queue):
133
138
134 self.id = str(id)
139 self.id = str(id)
135 self.project_id = project_id
140 self.project_id = project_id
136 self.name = name
141 self.name = name
137 self.type = 'other'
142 self.type = 'other'
138 self.err_queue = err_queue
143 self.err_queue = err_queue
139
144
140 def readXml(self, element, project_id, err_queue):
145 def readXml(self, element, project_id, err_queue):
141
146
142 self.id = element.get('id')
147 self.id = element.get('id')
143 self.name = element.get('name')
148 self.name = element.get('name')
144 self.type = 'other'
149 self.type = 'other'
145 self.project_id = str(project_id)
150 self.project_id = str(project_id)
146 self.err_queue = err_queue
151 self.err_queue = err_queue
147
152
148 for elm in element.iter('Parameter'):
153 for elm in element.iter('Parameter'):
149 self.addParameter(elm.get('name'), elm.get('value'))
154 self.addParameter(elm.get('name'), elm.get('value'))
150
155
151 def createObject(self):
156 def createObject(self):
152
157
153 className = eval(self.name)
158 className = eval(self.name)
154
159
155 if 'Plot' in self.name or 'Writer' in self.name or 'Send' in self.name or 'print' in self.name:
160 if 'Plot' in self.name or 'Writer' in self.name or 'Send' in self.name or 'print' in self.name:
156 kwargs = self.getKwargs()
161 kwargs = self.getKwargs()
157 opObj = className(self.id, self.id, self.project_id, self.err_queue, **kwargs)
162 opObj = className(self.id, self.id, self.project_id, self.err_queue, **kwargs)
158 opObj.start()
163 opObj.start()
159 self.type = 'external'
164 self.type = 'external'
160 else:
165 else:
161 opObj = className()
166 opObj = className()
162
167
163 self.object = opObj
168 self.object = opObj
164 return opObj
169 return opObj
165
170
166 class ProcUnitConf(ConfBase):
171 class ProcUnitConf(ConfBase):
167
172
168 ELEMENTNAME = 'ProcUnit'
173 ELEMENTNAME = 'ProcUnit'
169 xml_labels = ['id', 'inputId', 'name']
174 xml_labels = ['id', 'inputId', 'name']
170
175
171 def setup(self, project_id, id, name, datatype, inputId, err_queue):
176 def setup(self, project_id, id, name, datatype, inputId, err_queue):
172 '''
177 '''
173 '''
178 '''
174
179
175 if datatype == None and name == None:
180 if datatype == None and name == None:
176 raise ValueError('datatype or name should be defined')
181 raise ValueError('datatype or name should be defined')
177
182
178 if name == None:
183 if name == None:
179 if 'Proc' in datatype:
184 if 'Proc' in datatype:
180 name = datatype
185 name = datatype
181 else:
186 else:
182 name = '%sProc' % (datatype)
187 name = '%sProc' % (datatype)
183
188
184 if datatype == None:
189 if datatype == None:
185 datatype = name.replace('Proc', '')
190 datatype = name.replace('Proc', '')
186
191
187 self.id = str(id)
192 self.id = str(id)
188 self.project_id = project_id
193 self.project_id = project_id
189 self.name = name
194 self.name = name
190 self.datatype = datatype
195 self.datatype = datatype
191 self.inputId = inputId
196 self.inputId = inputId
192 self.err_queue = err_queue
197 self.err_queue = err_queue
193 self.operations = []
198 self.operations = []
194 self.parameters = {}
199 self.parameters = {}
195
200
196 def removeOperation(self, id):
201 def removeOperation(self, id):
197
202
198 i = [1 if x.id==id else 0 for x in self.operations]
203 i = [1 if x.id==id else 0 for x in self.operations]
199 self.operations.pop(i.index(1))
204 self.operations.pop(i.index(1))
200
205
201 def getOperation(self, id):
206 def getOperation(self, id):
202
207
203 for conf in self.operations:
208 for conf in self.operations:
204 if conf.id == id:
209 if conf.id == id:
205 return conf
210 return conf
206
211
207 def addOperation(self, name, optype='self'):
212 def addOperation(self, name, optype='self'):
208 '''
213 '''
209 '''
214 '''
210
215
211 id = self.getNewId()
216 id = self.getNewId()
212 conf = OperationConf()
217 conf = OperationConf()
213 conf.setup(id, name=name, priority='0', project_id=self.project_id, err_queue=self.err_queue)
218 conf.setup(id, name=name, priority='0', project_id=self.project_id, err_queue=self.err_queue)
214 self.operations.append(conf)
219 self.operations.append(conf)
215
220
216 return conf
221 return conf
217
222
218 def readXml(self, element, project_id, err_queue):
223 def readXml(self, element, project_id, err_queue):
219
224
220 self.id = element.get('id')
225 self.id = element.get('id')
221 self.name = element.get('name')
226 self.name = element.get('name')
222 self.inputId = None if element.get('inputId') == 'None' else element.get('inputId')
227 self.inputId = None if element.get('inputId') == 'None' else element.get('inputId')
223 self.datatype = element.get('datatype', self.name.replace(self.ELEMENTNAME.replace('Unit', ''), ''))
228 self.datatype = element.get('datatype', self.name.replace(self.ELEMENTNAME.replace('Unit', ''), ''))
224 self.project_id = str(project_id)
229 self.project_id = str(project_id)
225 self.err_queue = err_queue
230 self.err_queue = err_queue
226 self.operations = []
231 self.operations = []
227 self.parameters = {}
232 self.parameters = {}
228
233
229 for elm in element:
234 for elm in element:
230 if elm.tag == 'Parameter':
235 if elm.tag == 'Parameter':
231 self.addParameter(elm.get('name'), elm.get('value'))
236 self.addParameter(elm.get('name'), elm.get('value'))
232 elif elm.tag == 'Operation':
237 elif elm.tag == 'Operation':
233 conf = OperationConf()
238 conf = OperationConf()
234 conf.readXml(elm, project_id, err_queue)
239 conf.readXml(elm, project_id, err_queue)
235 self.operations.append(conf)
240 self.operations.append(conf)
236
241
237 def createObjects(self):
242 def createObjects(self):
238 '''
243 '''
239 Instancia de unidades de procesamiento.
244 Instancia de unidades de procesamiento.
240 '''
245 '''
241
246
242 className = eval(self.name)
247 className = eval(self.name)
243 kwargs = self.getKwargs()
248 kwargs = self.getKwargs()
244 procUnitObj = className()
249 procUnitObj = className()
245 procUnitObj.name = self.name
250 procUnitObj.name = self.name
246 log.success('creating process...', self.name)
251 log.success('creating process...', self.name)
247
252
248 for conf in self.operations:
253 for conf in self.operations:
249
254
250 opObj = conf.createObject()
255 opObj = conf.createObject()
251
256
252 log.success('adding operation: {}, type:{}'.format(
257 log.success('adding operation: {}, type:{}'.format(
253 conf.name,
258 conf.name,
254 conf.type), self.name)
259 conf.type), self.name)
255
260
256 procUnitObj.addOperation(conf, opObj)
261 procUnitObj.addOperation(conf, opObj)
257
262
258 self.object = procUnitObj
263 self.object = procUnitObj
259
264
260 def run(self):
265 def run(self):
261 '''
266 '''
262 '''
267 '''
263
268
264 return self.object.call(**self.getKwargs())
269 return self.object.call(**self.getKwargs())
265
270
266
271
267 class ReadUnitConf(ProcUnitConf):
272 class ReadUnitConf(ProcUnitConf):
268
273
269 ELEMENTNAME = 'ReadUnit'
274 ELEMENTNAME = 'ReadUnit'
270
275
271 def __init__(self):
276 def __init__(self):
272
277
273 self.id = None
278 self.id = None
274 self.datatype = None
279 self.datatype = None
275 self.name = None
280 self.name = None
276 self.inputId = None
281 self.inputId = None
277 self.operations = []
282 self.operations = []
278 self.parameters = {}
283 self.parameters = {}
279
284
280 def setup(self, project_id, id, name, datatype, err_queue, path='', startDate='', endDate='',
285 def setup(self, project_id, id, name, datatype, err_queue, path='', startDate='', endDate='',
281 startTime='', endTime='', server=None, **kwargs):
286 startTime='', endTime='', server=None, **kwargs):
282
287
283 if datatype == None and name == None:
288 if datatype == None and name == None:
284 raise ValueError('datatype or name should be defined')
289 raise ValueError('datatype or name should be defined')
285 if name == None:
290 if name == None:
286 if 'Reader' in datatype:
291 if 'Reader' in datatype:
287 name = datatype
292 name = datatype
288 datatype = name.replace('Reader','')
293 datatype = name.replace('Reader','')
289 else:
294 else:
290 name = '{}Reader'.format(datatype)
295 name = '{}Reader'.format(datatype)
291 if datatype == None:
296 if datatype == None:
292 if 'Reader' in name:
297 if 'Reader' in name:
293 datatype = name.replace('Reader','')
298 datatype = name.replace('Reader','')
294 else:
299 else:
295 datatype = name
300 datatype = name
296 name = '{}Reader'.format(name)
301 name = '{}Reader'.format(name)
297
302
298 self.id = id
303 self.id = id
299 self.project_id = project_id
304 self.project_id = project_id
300 self.name = name
305 self.name = name
301 self.datatype = datatype
306 self.datatype = datatype
302 self.err_queue = err_queue
307 self.err_queue = err_queue
303
308
304 self.addParameter(name='path', value=path)
309 self.addParameter(name='path', value=path)
305 self.addParameter(name='startDate', value=startDate)
310 self.addParameter(name='startDate', value=startDate)
306 self.addParameter(name='endDate', value=endDate)
311 self.addParameter(name='endDate', value=endDate)
307 self.addParameter(name='startTime', value=startTime)
312 self.addParameter(name='startTime', value=startTime)
308 self.addParameter(name='endTime', value=endTime)
313 self.addParameter(name='endTime', value=endTime)
309
314
310 for key, value in kwargs.items():
315 for key, value in kwargs.items():
311 self.addParameter(name=key, value=value)
316 self.addParameter(name=key, value=value)
312
317
313
318
314 class Project(Process):
319 class Project(Process):
320 """API to create signal chain projects"""
315
321
316 ELEMENTNAME = 'Project'
322 ELEMENTNAME = 'Project'
317
323
318 def __init__(self):
324 def __init__(self):
319
325
320 Process.__init__(self)
326 Process.__init__(self, name='')
321 self.id = None
327 self.id = '1'
328 if name:
329 self.name = '{} ({})'.format(Process.__name__, name)
322 self.filename = None
330 self.filename = None
323 self.description = None
331 self.description = None
324 self.email = None
332 self.email = None
325 self.alarm = []
333 self.alarm = []
326 self.configurations = {}
334 self.configurations = {}
327 # self.err_queue = Queue()
335 # self.err_queue = Queue()
328 self.err_queue = None
336 self.err_queue = None
329 self.started = False
337 self.started = False
330
338
331 def getNewId(self):
339 def getNewId(self):
332
340
333 idList = list(self.configurations.keys())
341 idList = list(self.configurations.keys())
334 id = int(self.id) * 10
342 id = int(self.id) * 10
335
343
336 while True:
344 while True:
337 id += 1
345 id += 1
338
346
339 if str(id) in idList:
347 if str(id) in idList:
340 continue
348 continue
341
349
342 break
350 break
343
351
344 return str(id)
352 return str(id)
345
353
346 def updateId(self, new_id):
354 def updateId(self, new_id):
347
355
348 self.id = str(new_id)
356 self.id = str(new_id)
349
357
350 keyList = list(self.configurations.keys())
358 keyList = list(self.configurations.keys())
351 keyList.sort()
359 keyList.sort()
352
360
353 n = 1
361 n = 1
354 new_confs = {}
362 new_confs = {}
355
363
356 for procKey in keyList:
364 for procKey in keyList:
357
365
358 conf = self.configurations[procKey]
366 conf = self.configurations[procKey]
359 idProcUnit = str(int(self.id) * 10 + n)
367 idProcUnit = str(int(self.id) * 10 + n)
360 conf.updateId(idProcUnit)
368 conf.updateId(idProcUnit)
361 new_confs[idProcUnit] = conf
369 new_confs[idProcUnit] = conf
362 n += 1
370 n += 1
363
371
364 self.configurations = new_confs
372 self.configurations = new_confs
365
373
366 def setup(self, id=1, name='', description='', email=None, alarm=[]):
374 def setup(self, id=1, name='', description='', email=None, alarm=[]):
367
375
368 self.id = str(id)
376 self.id = str(id)
369 self.description = description
377 self.description = description
370 self.email = email
378 self.email = email
371 self.alarm = alarm
379 self.alarm = alarm
372 if name:
380 if name:
373 self.name = '{} ({})'.format(Process.__name__, name)
381 self.name = '{} ({})'.format(Process.__name__, name)
374
382
375 def update(self, **kwargs):
383 def update(self, **kwargs):
376
384
377 for key, value in kwargs.items():
385 for key, value in kwargs.items():
378 setattr(self, key, value)
386 setattr(self, key, value)
379
387
380 def clone(self):
388 def clone(self):
381
389
382 p = Project()
390 p = Project()
383 p.id = self.id
391 p.id = self.id
384 p.name = self.name
392 p.name = self.name
385 p.description = self.description
393 p.description = self.description
386 p.configurations = self.configurations.copy()
394 p.configurations = self.configurations.copy()
387
395
388 return p
396 return p
389
397
390 def addReadUnit(self, id=None, datatype=None, name=None, **kwargs):
398 def addReadUnit(self, id=None, datatype=None, name=None, **kwargs):
391
399
392 '''
400 '''
393 '''
401 '''
394
402
395 if id is None:
403 if id is None:
396 idReadUnit = self.getNewId()
404 idReadUnit = self.getNewId()
397 else:
405 else:
398 idReadUnit = str(id)
406 idReadUnit = str(id)
399
407
400 conf = ReadUnitConf()
408 conf = ReadUnitConf()
401 conf.setup(self.id, idReadUnit, name, datatype, self.err_queue, **kwargs)
409 conf.setup(self.id, idReadUnit, name, datatype, self.err_queue, **kwargs)
402 self.configurations[conf.id] = conf
410 self.configurations[conf.id] = conf
403
411
404 return conf
412 return conf
405
413
406 def addProcUnit(self, id=None, inputId='0', datatype=None, name=None):
414 def addProcUnit(self, id=None, inputId='0', datatype=None, name=None):
407
415
408 '''
416 '''
409 '''
417 '''
410
418
411 if id is None:
419 if id is None:
412 idProcUnit = self.getNewId()
420 idProcUnit = self.getNewId()
413 else:
421 else:
414 idProcUnit = id
422 idProcUnit = id
415
423
416 conf = ProcUnitConf()
424 conf = ProcUnitConf()
417 conf.setup(self.id, idProcUnit, name, datatype, inputId, self.err_queue)
425 conf.setup(self.id, idProcUnit, name, datatype, inputId, self.err_queue)
418 self.configurations[conf.id] = conf
426 self.configurations[conf.id] = conf
419
427
420 return conf
428 return conf
421
429
422 def removeProcUnit(self, id):
430 def removeProcUnit(self, id):
423
431
424 if id in self.configurations:
432 if id in self.configurations:
425 self.configurations.pop(id)
433 self.configurations.pop(id)
426
434
427 def getReadUnit(self):
435 def getReadUnit(self):
428
436
429 for obj in list(self.configurations.values()):
437 for obj in list(self.configurations.values()):
430 if obj.ELEMENTNAME == 'ReadUnit':
438 if obj.ELEMENTNAME == 'ReadUnit':
431 return obj
439 return obj
432
440
433 return None
441 return None
434
442
435 def getProcUnit(self, id):
443 def getProcUnit(self, id):
436
444
437 return self.configurations[id]
445 return self.configurations[id]
438
446
439 def getUnits(self):
447 def getUnits(self):
440
448
441 keys = list(self.configurations)
449 keys = list(self.configurations)
442 keys.sort()
450 keys.sort()
443
451
444 for key in keys:
452 for key in keys:
445 yield self.configurations[key]
453 yield self.configurations[key]
446
454
447 def updateUnit(self, id, **kwargs):
455 def updateUnit(self, id, **kwargs):
448
456
449 conf = self.configurations[id].update(**kwargs)
457 conf = self.configurations[id].update(**kwargs)
450
458
451 def makeXml(self):
459 def makeXml(self):
452
460
453 xml = Element('Project')
461 xml = Element('Project')
454 xml.set('id', str(self.id))
462 xml.set('id', str(self.id))
455 xml.set('name', self.name)
463 xml.set('name', self.name)
456 xml.set('description', self.description)
464 xml.set('description', self.description)
457
465
458 for conf in self.configurations.values():
466 for conf in self.configurations.values():
459 conf.makeXml(xml)
467 conf.makeXml(xml)
460
468
461 self.xml = xml
469 self.xml = xml
462
470
463 def writeXml(self, filename=None):
471 def writeXml(self, filename=None):
464
472
465 if filename == None:
473 if filename == None:
466 if self.filename:
474 if self.filename:
467 filename = self.filename
475 filename = self.filename
468 else:
476 else:
469 filename = 'schain.xml'
477 filename = 'schain.xml'
470
478
471 if not filename:
479 if not filename:
472 print('filename has not been defined. Use setFilename(filename) for do it.')
480 print('filename has not been defined. Use setFilename(filename) for do it.')
473 return 0
481 return 0
474
482
475 abs_file = os.path.abspath(filename)
483 abs_file = os.path.abspath(filename)
476
484
477 if not os.access(os.path.dirname(abs_file), os.W_OK):
485 if not os.access(os.path.dirname(abs_file), os.W_OK):
478 print('No write permission on %s' % os.path.dirname(abs_file))
486 print('No write permission on %s' % os.path.dirname(abs_file))
479 return 0
487 return 0
480
488
481 if os.path.isfile(abs_file) and not(os.access(abs_file, os.W_OK)):
489 if os.path.isfile(abs_file) and not(os.access(abs_file, os.W_OK)):
482 print('File %s already exists and it could not be overwriten' % abs_file)
490 print('File %s already exists and it could not be overwriten' % abs_file)
483 return 0
491 return 0
484
492
485 self.makeXml()
493 self.makeXml()
486
494
487 ElementTree(self.xml).write(abs_file, method='xml')
495 ElementTree(self.xml).write(abs_file, method='xml')
488
496
489 self.filename = abs_file
497 self.filename = abs_file
490
498
491 return 1
499 return 1
492
500
493 def readXml(self, filename):
501 def readXml(self, filename):
494
502
495 abs_file = os.path.abspath(filename)
503 abs_file = os.path.abspath(filename)
496
504
497 self.configurations = {}
505 self.configurations = {}
498
506
499 try:
507 try:
500 self.xml = ElementTree().parse(abs_file)
508 self.xml = ElementTree().parse(abs_file)
501 except:
509 except:
502 log.error('Error reading %s, verify file format' % filename)
510 log.error('Error reading %s, verify file format' % filename)
503 return 0
511 return 0
504
512
505 self.id = self.xml.get('id')
513 self.id = self.xml.get('id')
506 self.name = self.xml.get('name')
514 self.name = self.xml.get('name')
507 self.description = self.xml.get('description')
515 self.description = self.xml.get('description')
508
516
509 for element in self.xml:
517 for element in self.xml:
510 if element.tag == 'ReadUnit':
518 if element.tag == 'ReadUnit':
511 conf = ReadUnitConf()
519 conf = ReadUnitConf()
512 conf.readXml(element, self.id, self.err_queue)
520 conf.readXml(element, self.id, self.err_queue)
513 self.configurations[conf.id] = conf
521 self.configurations[conf.id] = conf
514 elif element.tag == 'ProcUnit':
522 elif element.tag == 'ProcUnit':
515 conf = ProcUnitConf()
523 conf = ProcUnitConf()
516 input_proc = self.configurations[element.get('inputId')]
524 input_proc = self.configurations[element.get('inputId')]
517 conf.readXml(element, self.id, self.err_queue)
525 conf.readXml(element, self.id, self.err_queue)
518 self.configurations[conf.id] = conf
526 self.configurations[conf.id] = conf
519
527
520 self.filename = abs_file
528 self.filename = abs_file
521
529
522 return 1
530 return 1
523
531
524 def __str__(self):
532 def __str__(self):
525
533
526 text = '\nProject[id=%s, name=%s, description=%s]\n\n' % (
534 text = '\nProject[id=%s, name=%s, description=%s]\n\n' % (
527 self.id,
535 self.id,
528 self.name,
536 self.name,
529 self.description,
537 self.description,
530 )
538 )
531
539
532 for conf in self.configurations.values():
540 for conf in self.configurations.values():
533 text += '{}'.format(conf)
541 text += '{}'.format(conf)
534
542
535 return text
543 return text
536
544
537 def createObjects(self):
545 def createObjects(self):
538
546
539 keys = list(self.configurations.keys())
547 keys = list(self.configurations.keys())
540 keys.sort()
548 keys.sort()
541 for key in keys:
549 for key in keys:
542 conf = self.configurations[key]
550 conf = self.configurations[key]
543 conf.createObjects()
551 conf.createObjects()
544 if conf.inputId is not None:
552 if conf.inputId is not None:
545 conf.object.setInput(self.configurations[conf.inputId].object)
553 conf.object.setInput(self.configurations[conf.inputId].object)
546
554
547 def monitor(self):
555 def monitor(self):
548
556
549 t = Thread(target=self._monitor, args=(self.err_queue, self.ctx))
557 t = Thread(target=self._monitor, args=(self.err_queue, self.ctx))
550 t.start()
558 t.start()
551
559
552 def _monitor(self, queue, ctx):
560 def _monitor(self, queue, ctx):
553
561
554 import socket
562 import socket
555
563
556 procs = 0
564 procs = 0
557 err_msg = ''
565 err_msg = ''
558
566
559 while True:
567 while True:
560 msg = queue.get()
568 msg = queue.get()
561 if '#_start_#' in msg:
569 if '#_start_#' in msg:
562 procs += 1
570 procs += 1
563 elif '#_end_#' in msg:
571 elif '#_end_#' in msg:
564 procs -=1
572 procs -=1
565 else:
573 else:
566 err_msg = msg
574 err_msg = msg
567
575
568 if procs == 0 or 'Traceback' in err_msg:
576 if procs == 0 or 'Traceback' in err_msg:
569 break
577 break
570 time.sleep(0.1)
578 time.sleep(0.1)
571
579
572 if '|' in err_msg:
580 if '|' in err_msg:
573 name, err = err_msg.split('|')
581 name, err = err_msg.split('|')
574 if 'SchainWarning' in err:
582 if 'SchainWarning' in err:
575 log.warning(err.split('SchainWarning:')[-1].split('\n')[0].strip(), name)
583 log.warning(err.split('SchainWarning:')[-1].split('\n')[0].strip(), name)
576 elif 'SchainError' in err:
584 elif 'SchainError' in err:
577 log.error(err.split('SchainError:')[-1].split('\n')[0].strip(), name)
585 log.error(err.split('SchainError:')[-1].split('\n')[0].strip(), name)
578 else:
586 else:
579 log.error(err, name)
587 log.error(err, name)
580 else:
588 else:
581 name, err = self.name, err_msg
589 name, err = self.name, err_msg
582
590
583 time.sleep(1)
591 time.sleep(1)
584
592
585 ctx.term()
593 ctx.term()
586
594
587 message = ''.join(err)
595 message = ''.join(err)
588
596
589 if err_msg:
597 if err_msg:
590 subject = 'SChain v%s: Error running %s\n' % (
598 subject = 'SChain v%s: Error running %s\n' % (
591 schainpy.__version__, self.name)
599 schainpy.__version__, self.name)
592
600
593 subtitle = 'Hostname: %s\n' % socket.gethostbyname(
601 subtitle = 'Hostname: %s\n' % socket.gethostbyname(
594 socket.gethostname())
602 socket.gethostname())
595 subtitle += 'Working directory: %s\n' % os.path.abspath('./')
603 subtitle += 'Working directory: %s\n' % os.path.abspath('./')
596 subtitle += 'Configuration file: %s\n' % self.filename
604 subtitle += 'Configuration file: %s\n' % self.filename
597 subtitle += 'Time: %s\n' % str(datetime.datetime.now())
605 subtitle += 'Time: %s\n' % str(datetime.datetime.now())
598
606
599 readUnitConfObj = self.getReadUnit()
607 readUnitConfObj = self.getReadUnit()
600 if readUnitConfObj:
608 if readUnitConfObj:
601 subtitle += '\nInput parameters:\n'
609 subtitle += '\nInput parameters:\n'
602 subtitle += '[Data path = %s]\n' % readUnitConfObj.parameters['path']
610 subtitle += '[Data path = %s]\n' % readUnitConfObj.parameters['path']
603 subtitle += '[Start date = %s]\n' % readUnitConfObj.parameters['startDate']
611 subtitle += '[Start date = %s]\n' % readUnitConfObj.parameters['startDate']
604 subtitle += '[End date = %s]\n' % readUnitConfObj.parameters['endDate']
612 subtitle += '[End date = %s]\n' % readUnitConfObj.parameters['endDate']
605 subtitle += '[Start time = %s]\n' % readUnitConfObj.parameters['startTime']
613 subtitle += '[Start time = %s]\n' % readUnitConfObj.parameters['startTime']
606 subtitle += '[End time = %s]\n' % readUnitConfObj.parameters['endTime']
614 subtitle += '[End time = %s]\n' % readUnitConfObj.parameters['endTime']
607
615
608 a = Alarm(
616 a = Alarm(
609 modes=self.alarm,
617 modes=self.alarm,
610 email=self.email,
618 email=self.email,
611 message=message,
619 message=message,
612 subject=subject,
620 subject=subject,
613 subtitle=subtitle,
621 subtitle=subtitle,
614 filename=self.filename
622 filename=self.filename
615 )
623 )
616
624
617 a.start()
625 a.start()
618
626
619 def setFilename(self, filename):
627 def setFilename(self, filename):
620
628
621 self.filename = filename
629 self.filename = filename
622
630
623 def runProcs(self):
631 def runProcs(self):
624
632
625 err = False
633 err = False
626 n = len(self.configurations)
634 n = len(self.configurations)
627
635
628 while not err:
636 while not err:
629 for conf in self.getUnits():
637 for conf in self.getUnits():
630 ok = conf.run()
638 ok = conf.run()
631 if ok is 'Error':
639 if ok is 'Error':
632 n -= 1
640 n -= 1
633 continue
641 continue
634 elif not ok:
642 elif not ok:
635 break
643 break
636 if n == 0:
644 if n == 0:
637 err = True
645 err = True
638
646
639 def run(self):
647 def run(self):
640
648
641 log.success('\nStarting Project {} [id={}]'.format(self.name, self.id), tag='')
649 log.success('\nStarting Project {} [id={}]'.format(self.name, self.id), tag='')
642 self.started = True
650 self.started = True
643 self.start_time = time.time()
651 self.start_time = time.time()
644 self.createObjects()
652 self.createObjects()
645 self.runProcs()
653 self.runProcs()
646 log.success('{} Done (Time: {:4.2f}s)'.format(
654 log.success('{} Done (Time: {:4.2f}s)'.format(
647 self.name,
655 self.name,
648 time.time()-self.start_time), '')
656 time.time()-self.start_time), '')
@@ -1,63 +1,86
1 '''
1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
2 Created on Jul 16, 2014
2 # All rights reserved.
3 #
4 # Distributed under the terms of the BSD 3-clause license.
5 """schainpy is an open source library to read, write and process radar data
3
6
4 @author: Miguel Urco
7 Signal Chain is a radar data processing library wich includes modules to read,
5 @author: Juan C. Espinoza
8 and write different files formats, besides modules to process and visualize the
6 '''
9 data.
10 """
7
11
8 import os
12 import os
9 from setuptools import setup, Extension
13 from setuptools import setup, Extension
10 from setuptools.command.build_ext import build_ext as _build_ext
14 from setuptools.command.build_ext import build_ext as _build_ext
11 from schainpy import __version__
15 from schainpy import __version__
12
16
17 DOCLINES = __doc__.split("\n")
18
13 class build_ext(_build_ext):
19 class build_ext(_build_ext):
14 def finalize_options(self):
20 def finalize_options(self):
15 _build_ext.finalize_options(self)
21 _build_ext.finalize_options(self)
16 # Prevent numpy from thinking it is still in its setup process:
22 # Prevent numpy from thinking it is still in its setup process:
17 __builtins__.__NUMPY_SETUP__ = False
23 __builtins__.__NUMPY_SETUP__ = False
18 import numpy
24 import numpy
19 self.include_dirs.append(numpy.get_include())
25 self.include_dirs.append(numpy.get_include())
20
26
21 setup(
27 setup(
22 name = "schainpy",
28 name = "schainpy",
23 version = __version__,
29 version = __version__,
24 description = "Python tools to read, write and process Jicamarca data",
30 description = DOCLINES[0],
25 author = "Miguel Urco, Juan C. Espinoza",
31 long_description = "\n".join(DOCLINES[2:]),
26 author_email = "juan.espinoza@jro.igp.gob.pe",
32 url = "https://github.com/JRO-Peru/schain",
27 url = "http://jro-dev.igp.gob.pe/rhodecode/schain",
33 author = "Jicamarca Radio Observatory",
34 author_email = "jro-developers@igp.gob.pe",
35 license="BSD-3-Clause",
36 classifiers=[
37 "Development Status :: 4 - Beta",
38 "Environment :: Console",
39 "Intended Audience :: Science/Research",
40 "License :: OSI Approved :: BSD License",
41 "Operating System :: MacOS :: MacOS X",
42 "Operating System :: POSIX :: Linux",
43 "Programming Language :: Python :: 2",
44 "Programming Language :: Python :: 2.7",
45 "Programming Language :: Python :: 3",
46 "Programming Language :: Python :: 3.5",
47 "Programming Language :: Python :: 3.6",
48 "Programming Language :: Python :: 3.7",
49 "Topic :: Scientific/Engineering",
50 ],
28 packages = {
51 packages = {
29 'schainpy',
52 'schainpy',
30 'schainpy.model',
53 'schainpy.model',
31 'schainpy.model.data',
54 'schainpy.model.data',
32 'schainpy.model.graphics',
55 'schainpy.model.graphics',
33 'schainpy.model.io',
56 'schainpy.model.io',
34 'schainpy.model.proc',
57 'schainpy.model.proc',
35 'schainpy.model.utils',
58 'schainpy.model.utils',
36 'schainpy.utils',
59 'schainpy.utils',
37 'schainpy.gui',
60 'schainpy.gui',
38 'schainpy.cli',
61 'schainpy.cli',
39 },
62 },
40 package_data = {'': ['schain.conf.template'],
63 package_data = {'': ['schain.conf.template'],
41 'schainpy.files': ['*.oga']
64 'schainpy.files': ['*.oga']
42 },
65 },
43 include_package_data = False,
66 include_package_data = False,
44 scripts = ['schainpy/gui/schainGUI'],
67 scripts = ['schainpy/gui/schainGUI'],
45 entry_points = {
68 entry_points = {
46 'console_scripts': [
69 'console_scripts': [
47 'schain = schainpy.cli.cli:main',
70 'schain = schainpy.cli.cli:main',
48 ],
71 ],
49 },
72 },
50 cmdclass = {'build_ext': build_ext},
73 cmdclass = {'build_ext': build_ext},
51 ext_modules=[
74 ext_modules=[
52 Extension("schainpy.model.data._noise", ["schainc/_noise.c"]),
75 Extension("schainpy.model.data._noise", ["schainc/_noise.c"]),
53 ],
76 ],
54 setup_requires = ["numpy"],
77 setup_requires = ["numpy"],
55 install_requires = [
78 install_requires = [
56 "scipy",
79 "scipy",
57 "h5py",
80 "h5py",
58 "matplotlib",
81 "matplotlib",
59 "pyzmq",
82 "pyzmq",
60 "fuzzywuzzy",
83 "fuzzywuzzy",
61 "click",
84 "click",
62 ],
85 ],
63 )
86 )
General Comments 0
You need to be logged in to leave comments. Login now