Line data Source code
1 : //# FlagAgentDisplay.cc: This file contains the implementation of the FlagAgentDisplay class.
2 : //#
3 : //# CASA - Common Astronomy Software Applications (http://casa.nrao.edu/)
4 : //# Copyright (C) Associated Universities, Inc. Washington DC, USA 2011, All rights reserved.
5 : //# Copyright (C) European Southern Observatory, 2011, All rights reserved.
6 : //#
7 : //# This library is free software; you can redistribute it and/or
8 : //# modify it under the terms of the GNU Lesser General Public
9 : //# License as published by the Free software Foundation; either
10 : //# version 2.1 of the License, or (at your option) any later version.
11 : //#
12 : //# This library is distributed in the hope that it will be useful,
13 : //# but WITHOUT ANY WARRANTY, without even the implied warranty of
14 : //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : //# Lesser General Public License for more details.
16 : //#
17 : //# You should have received a copy of the GNU Lesser General Public
18 : //# License along with this library; if not, write to the Free Software
19 : //# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 : //# MA 02111-1307 USA
21 : //# $Id: rurvashi 28 Nov 2011$
22 :
23 : #include <array>
24 : #include <thread>
25 : #include <unistd.h>
26 : #include <sys/types.h>
27 : #include <sys/wait.h>
28 : #include <casatools/Config/State.h>
29 :
30 : #ifdef USE_GRPC
31 : #include <flagging/Flagging/grpcFlagAgentDisplay.h>
32 : #include <grpc++/grpc++.h>
33 : #include "shutdown.grpc.pb.h"
34 : #include "ping.grpc.pb.h"
35 :
36 : using namespace casacore;
37 : namespace casa { //# NAMESPACE CASA - BEGIN
38 :
39 : constexpr int FlagAgentDisplay::TIMEOUT;
40 :
41 : // https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
42 : // C++ is so ridiculous... trim from start (in place)
43 0 : static inline void ltrim(std::string &s) {
44 0 : s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
45 0 : return !std::isspace(ch);
46 : }));
47 0 : }
48 :
49 : // trim from end (in place)
50 0 : static inline void rtrim(std::string &s) {
51 0 : s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
52 0 : return !std::isspace(ch);
53 0 : }).base(), s.end());
54 0 : }
55 :
56 : // trim from both ends (in place)
57 0 : static inline void trim(std::string &s) {
58 0 : ltrim(s);
59 0 : rtrim(s);
60 0 : }
61 :
62 0 : static bool isdir( const char *path ) {
63 : struct stat statbuf;
64 0 : int err = stat(path, &statbuf);
65 0 : if ( err == -1 ) return false;
66 0 : if ( S_ISDIR(statbuf.st_mode) ) return true;
67 0 : return false;
68 : }
69 :
70 0 : static std::string trim_trailing_slash( const char *str ) {
71 0 : char *temp = strdup(str);
72 0 : for ( int off = strlen(str) - 1; off >= 0; --off ) {
73 0 : if ( temp[off] == '/' ) temp[off] = '\0';
74 0 : else break;
75 : }
76 0 : std::string result = temp;
77 0 : free(temp);
78 0 : return result;
79 : }
80 :
81 0 : grpcFlagAgentState::grpcFlagAgentState( ) : userChoice_p("Continue"), userFixA1_p(""), userFixA2_p(""),
82 0 : skipScan_p(-1), skipSpw_p(-1), skipField_p(-1),
83 0 : antenna1_p(""),antenna2_p(""), input_received(false) { }
84 :
85 0 : ::grpc::Status grpcFlagAgentResponse::button( ::grpc::ServerContext *context,
86 : const ::rpc::gui::ButtonEvent *req,
87 : ::google::protobuf::Empty* ) {
88 0 : static const auto debug = getenv("GRPC_DEBUG");
89 0 : if ( debug ) {
90 0 : std::cerr << "plotserver '" << req->name( ) << "' button event received " <<
91 0 : " (process " << getpid( ) << ", thread " <<
92 0 : std::this_thread::get_id() << ")" << std::endl;
93 0 : fflush(stderr);
94 : }
95 :
96 : // Manage buttons from: Data Plot Window
97 0 : if ( req->name( ) == "NextBaseline" || req->name( ) == "PrevBaseline" ||
98 0 : req->name( ) == "NextScan" || req->name( ) == "NextField" ||
99 0 : req->name( ) == "NextSpw" || req->name( ) == "StopDisplay" || req->name( ) == "Quit") {
100 0 : std::lock_guard<std::mutex> lock(state->set_values);
101 0 : state->userChoice_p = req->name( ); // set input
102 0 : state->input_received = true; // set whenever state object is modified
103 0 : if ( state->input_needed ) {
104 0 : state->input_needed = false; // prevent setting future twice
105 0 : state->output.set_value(true); // signal controlling thread that wait is over
106 : }
107 :
108 : // Manage buttons from: Report Plot Window
109 0 : } else if ( req->name( ) == "Next" || req->name( ) == "Prev" || req->name( ) == "Quit") {
110 0 : std::lock_guard<std::mutex> lock(state->set_values);
111 0 : state->userChoice_p = req->name( ); // set input
112 0 : state->input_received = true; // set whenever state object is modified
113 0 : if ( state->input_needed ) {
114 0 : state->input_needed = false; // prevent setting future twice
115 0 : state->output.set_value(true); // signal controlling thread that wait is over
116 : }
117 0 : }
118 :
119 0 : return grpc::Status::OK;
120 : }
121 0 : ::grpc::Status grpcFlagAgentResponse::check( ::grpc::ServerContext *context,
122 : const ::rpc::gui::CheckEvent *req,
123 : ::google::protobuf::Empty* ) {
124 0 : static const auto debug = getenv("GRPC_DEBUG");
125 0 : if ( debug ) {
126 0 : std::cerr << "plotserver " << req->name( ) <<
127 0 : " [" << req->state( ) << "] check event received " <<
128 0 : " (process " << getpid( ) << ", thread " <<
129 0 : std::this_thread::get_id() << ")" << std::endl;
130 0 : fflush(stderr);
131 : }
132 :
133 : // Manage check boxes from: Data Plot Window
134 0 : if ( req->name( ) == "FixAntenna1" ) {
135 0 : std::lock_guard<std::mutex> lock(state->set_values);
136 0 : state->userFixA1_p = (req->state( ) == 0) ? "" : state->antenna1_p;
137 0 : } else if ( req->name( ) == "FixAntenna2" ) {
138 0 : std::lock_guard<std::mutex> lock(state->set_values);
139 0 : state->userFixA2_p = (req->state( ) == 0 ) ? "" : state->antenna2_p;
140 0 : }
141 0 : return grpc::Status::OK;
142 : }
143 0 : ::grpc::Status grpcFlagAgentResponse::radio( ::grpc::ServerContext *context,
144 : const ::rpc::gui::RadioEvent *req,
145 : ::google::protobuf::Empty* ) {
146 0 : static const auto debug = getenv("GRPC_DEBUG");
147 0 : if ( debug ) {
148 0 : std::cerr << "plotserver " << req->name( ) <<
149 0 : " [" << req->state( ) << "] radio event received " <<
150 0 : " (process " << getpid( ) << ", thread " <<
151 0 : std::this_thread::get_id() << ")" << std::endl;
152 0 : fflush(stderr);
153 : }
154 0 : return grpc::Status::OK;
155 : }
156 0 : ::grpc::Status grpcFlagAgentResponse::linetext( ::grpc::ServerContext *context,
157 : const ::rpc::gui::LineTextEvent *req,
158 : ::google::protobuf::Empty* ) {
159 0 : static const auto debug = getenv("GRPC_DEBUG");
160 0 : if ( debug ) {
161 0 : std::cerr << "plotserver " << req->name( ) <<
162 0 : " [" << req->text( ) << "] linetext event received " <<
163 0 : " (process " << getpid( ) << ", thread " <<
164 0 : std::this_thread::get_id() << ")" << std::endl;
165 0 : fflush(stderr);
166 : }
167 0 : return grpc::Status::OK;
168 : }
169 0 : ::grpc::Status grpcFlagAgentResponse::slidevalue( ::grpc::ServerContext *context,
170 : const ::rpc::gui::SlideValueEvent *req,
171 : ::google::protobuf::Empty* ) {
172 0 : static const auto debug = getenv("GRPC_DEBUG");
173 0 : if ( debug ) {
174 0 : std::cerr << "plotserver " << req->name( ) <<
175 0 : "[" << req->value( ) << "] slidevalue event received " <<
176 0 : " (process " << getpid( ) << ", thread " <<
177 0 : std::this_thread::get_id() << ")" << std::endl;
178 0 : fflush(stderr);
179 : }
180 0 : return grpc::Status::OK;
181 : }
182 0 : ::grpc::Status grpcFlagAgentResponse::exiting( ::grpc::ServerContext *context,
183 : const ::google::protobuf::Empty*,
184 : ::google::protobuf::Empty* ) {
185 0 : static const auto debug = getenv("GRPC_DEBUG");
186 0 : if ( debug ) {
187 : std::cerr << "plotserver exiting event received " <<
188 0 : " (process " << getpid( ) << ", thread " <<
189 0 : std::this_thread::get_id() << ")" << std::endl;
190 0 : fflush(stderr);
191 : }
192 0 : return grpc::Status::OK;
193 : }
194 0 : ::grpc::Status grpcFlagAgentResponse::closing( ::grpc::ServerContext *context,
195 : const ::rpc::gui::ClosingEvent *req,
196 : ::google::protobuf::Empty* ){
197 0 : static const auto debug = getenv("GRPC_DEBUG");
198 0 : if ( debug ) {
199 : std::cerr << "plotserver closing event received " <<
200 0 : " (process " << getpid( ) << ", thread " <<
201 0 : std::this_thread::get_id() << ")" << std::endl;
202 0 : fflush(stderr);
203 : }
204 :
205 0 : std::lock_guard<std::mutex> lock(state->set_values);
206 0 : state->userChoice_p = "Quit"; // user stopped GUI
207 0 : state->input_received = true; // set whenever state object is modified
208 0 : if ( state->input_needed ) {
209 0 : state->input_needed = false; // prevent setting future twice
210 0 : state->output.set_value(true); // signal controlling thread that wait is over
211 : }
212 0 : return grpc::Status::OK;
213 0 : }
214 :
215 0 : std::string FlagAgentDisplay::plotter_t::get_casaplotserver_path( ) const {
216 0 : static std::string python_path = casatools::get_state( ).pythonPath( );
217 : //*** python3 -m casaplotserver --app-path
218 0 : char python_cmd[python_path.size( ) + 35];
219 0 : sprintf( python_cmd, "%s -m casaplotserver --app-path", python_path.c_str( ) );
220 : std::array<char, 512> buffer;
221 0 : std::string result;
222 0 : std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(python_cmd, "r"), pclose);
223 0 : if ( ! pipe ) return std::string( ); //*** failed to start python
224 0 : while ( fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr ) {
225 0 : result += buffer.data();
226 : }
227 0 : trim(result);
228 0 : if ( result.size( ) == 0 ) return std::string( );
229 0 : return result;
230 0 : }
231 :
232 0 : std::string FlagAgentDisplay::plotter_t::get_fifo( ) const {
233 0 : static const char *env_tmpdir = getenv("TMPDIR");
234 0 : static std::string fifo_template = trim_trailing_slash(env_tmpdir && isdir(env_tmpdir) ? env_tmpdir : P_tmpdir) + "/cps-XXXXXXXXXX";
235 0 : static int fifo_template_size = fifo_template.size( );
236 0 : char fifo_path[fifo_template_size+1];
237 0 : strncpy( fifo_path, fifo_template.c_str( ), fifo_template_size );
238 0 : fifo_path[fifo_template_size] = '\0';
239 0 : int fd = mkstemp(fifo_path);
240 0 : if ( fd == -1 ) throw std::runtime_error("mkstemp failed...");
241 0 : close( fd );
242 0 : unlink(fifo_path);
243 0 : mkfifo( fifo_path, 0666 );
244 0 : return fifo_path;
245 0 : }
246 :
247 0 : bool FlagAgentDisplay::plotter_t::start_response_manager( ) {
248 0 : static const auto debug = getenv("GRPC_DEBUG");
249 : //***
250 : //*** set up a default address (grpc picks port) and address buffers
251 : //***
252 : char address_buf[100];
253 0 : constexpr char address_template[] = "0.0.0.0:%d";
254 0 : snprintf(address_buf,sizeof(address_buf),address_template,0);
255 0 : std::string server_address(address_buf);
256 0 : int selected_port = 0;
257 :
258 : //***
259 : //*** build grpc service
260 : //***
261 0 : grpc::ServerBuilder builder;
262 : // Listen on the given address without any authentication mechanism.
263 0 : builder.AddListeningPort(server_address, grpc::InsecureServerCredentials(), &selected_port);
264 : // Register "service" as the instance through which we'll receive from
265 : // the plot server client.
266 0 : builder.RegisterService(response_svc.get( ));
267 :
268 : // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
269 : // Launch server...
270 0 : response_server = builder.BuildAndStart( );
271 0 : if ( selected_port > 0 ) {
272 : // if an available port can be found, selected_port is set to a value greater than zero
273 0 : snprintf(address_buf,sizeof(address_buf),address_template,selected_port);
274 0 : response_uri = address_buf;
275 0 : if ( debug ) {
276 0 : std::cerr << "flagagentdisplay response service available at " << response_uri << std::endl;
277 0 : fflush(stdout);
278 : }
279 0 : return true;
280 : }
281 0 : return false;
282 0 : }
283 :
284 0 : bool FlagAgentDisplay::plotter_t::launch(std::string plotserver_path) {
285 0 : static const auto debug = getenv("GRPC_DEBUG");
286 :
287 0 : std::string fifo = get_fifo( );
288 0 : if ( fifo.size( ) == 0 ) return false;
289 :
290 : // plot server will generate events (formerly DBus signals)
291 : // in response to GUI operations...
292 0 : if ( start_response_manager( ) == false ) return false;
293 :
294 : // here we start the viewer in a very basic manner... we do not bother
295 : // with all of the theatrics needed to daemonize the launched process
296 : // (see https://stackoverflow.com/questions/17954432/creating-a-daemon-in-linux)
297 : // it could be that this should be done in the future, but for now we
298 : // will adopt the simple...
299 :
300 : // casaplotserver --server=<FIFO-or-GRPC> --event-uri=<GRPC> [ --datapath=<PATH> --casalog=<PATH> ]
301 :
302 0 : int argc = 3;
303 0 : int logarg = argc; // if a log file is specfied it comes last...
304 0 : std::string log_path = casatools::get_state( ).logPath( );
305 0 : if ( log_path.size( ) > 0 ) ++argc;
306 0 : char **arguments = (char**) malloc(sizeof(char*) * (argc + 1));
307 :
308 0 : arguments[argc] = 0;
309 0 : arguments[0] = strdup(plotserver_path.c_str( ));
310 0 : arguments[1] = (char*) malloc(sizeof(char) * (fifo.size( ) + 12));
311 0 : sprintf( arguments[1], "--server=%s", fifo.c_str( ) );
312 0 : arguments[2] = (char*) malloc(sizeof(char) * (response_uri.size( ) + 18));
313 0 : sprintf( arguments[2], "--event-uri=%s", response_uri.c_str( ) );
314 0 : if ( log_path.size( ) > 0 ) {
315 0 : arguments[logarg] = (char*) malloc(sizeof(char) * (log_path.size( ) + 17));
316 0 : sprintf( arguments[logarg], "--logfile=%s", log_path.c_str( ) );
317 : }
318 :
319 0 : if ( debug ) {
320 0 : std::cerr << "forking plotserver process: ";
321 0 : for (int i=0; i < argc; ++i) std::cerr << arguments[i] << " ";
322 0 : std::cerr << " (process " << getpid( ) << ", thread " <<
323 0 : std::this_thread::get_id() << ")" << std::endl;
324 0 : fflush(stderr);
325 : }
326 0 : pid_t newpid = fork( );
327 :
328 0 : if ( newpid == 0 ) {
329 0 : if ( debug ) {
330 0 : std::cerr << "execing plotserver process: ";
331 0 : for (int i=0; i < argc; ++i) std::cerr << arguments[i] << " ";
332 0 : std::cerr << " (process " << getpid( ) << ", thread " <<
333 0 : std::this_thread::get_id() << ")" << std::endl;
334 0 : fflush(stderr);
335 : }
336 0 : execvp( arguments[0], (char* const*) arguments );
337 0 : perror( "FlagAgentDisplay::plotter_t::launch(...) child process exec failed" );
338 0 : exit(1);
339 : }
340 :
341 0 : for ( int i=0; i < argc; ++i ) free(arguments[i]);
342 0 : free(arguments);
343 :
344 0 : if ( newpid == -1 ) {
345 0 : perror( "FlagAgentDisplay::plotter_t::launch(...) child process fork failed" );
346 0 : return false;
347 : }
348 :
349 : // perform a health check, after a delay...
350 : int status;
351 0 : sleep(2);
352 0 : pid_t w = waitpid( newpid, &status, WUNTRACED | WCONTINUED | WNOHANG );
353 0 : if ( w == -1 ){
354 0 : if ( debug ) {
355 : std::cerr << "plotserver process failed " <<
356 0 : " (process " << getpid( ) << ", thread " <<
357 0 : std::this_thread::get_id() << ")" << std::endl;
358 0 : fflush(stderr);
359 : }
360 : // waitpid failed
361 0 : return false;
362 0 : } else if ( w != 0 ) {
363 0 : if ( debug ) {
364 : std::cerr << "plotserver process died " <<
365 0 : " (process " << getpid( ) << ", thread " <<
366 0 : std::this_thread::get_id() << ")" << std::endl;
367 0 : fflush(stderr);
368 : }
369 : // process exited
370 0 : if ( WIFEXITED(status) ) {
371 0 : printf("exited, status=%d\n", WEXITSTATUS(status));
372 0 : } else if (WIFSIGNALED(status)) {
373 0 : printf("killed by signal %d\n", WTERMSIG(status));
374 0 : } else if (WIFSTOPPED(status)) {
375 0 : printf("stopped by signal %d\n", WSTOPSIG(status));
376 : }
377 0 : return false;
378 : }
379 :
380 0 : if ( debug ) {
381 : std::cerr << "fetching casaplotserver uri from " << fifo <<
382 0 : " (process " << getpid( ) << ", thread " <<
383 0 : std::this_thread::get_id() << ")" << std::endl;
384 0 : fflush(stderr);
385 : }
386 :
387 : char buffer[512];
388 0 : std::string uri_buffer;
389 0 : FILE *fp = fopen(fifo.c_str( ), "r");
390 0 : while ( fgets( buffer, sizeof(buffer), fp ) ) { uri_buffer = uri_buffer + buffer; }
391 0 : fclose(fp);
392 0 : trim(uri_buffer);
393 :
394 : // validate viewer uri...
395 0 : if ( ! std::regex_match( uri_buffer, std::regex("^([0-9]+\\.){3}[0-9]+:[0-9]+$") ) ) {
396 : //rework of regex required for IPv6...
397 0 : if ( debug ) {
398 : std::cerr << "bad casaplotserver uri " << uri_buffer <<
399 0 : " (process " << getpid( ) << ", thread " <<
400 0 : std::this_thread::get_id() << ")" << std::endl;
401 0 : fflush(stderr);
402 : }
403 0 : return false;
404 : }
405 :
406 0 : if ( debug ) {
407 : std::cerr << "received casaplotserver uri: " << uri_buffer <<
408 0 : " (process " << getpid( ) << ", thread " <<
409 0 : std::this_thread::get_id() << ")" << std::endl;
410 0 : fflush(stderr);
411 : }
412 :
413 0 : plot_uri = uri_buffer;
414 0 : pid = newpid;
415 0 : if ( debug ) {
416 0 : std::cerr << "creating plotserver stub: " << plot_uri <<
417 0 : " (process " << getpid( ) << ", thread " <<
418 0 : std::this_thread::get_id() << ")" << std::endl;
419 0 : fflush(stderr);
420 : }
421 0 : plot = rpc::gui::plotserver::NewStub( grpc::CreateChannel( plot_uri,
422 0 : grpc::InsecureChannelCredentials( ) ) );
423 :
424 0 : grpc::ClientContext context;
425 0 : ::google::protobuf::Empty resp;
426 0 : ::google::protobuf::Empty msg;
427 0 : auto ping = casatools::rpc::Ping::NewStub( grpc::CreateChannel( plot_uri, grpc::InsecureChannelCredentials( ) ) );
428 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
429 0 : context.set_deadline(deadline);
430 0 : ::grpc::Status st = ping->now( &context, msg, &resp );
431 0 : bool ping_result = st.ok( );
432 0 : if ( debug ) {
433 : std::cerr << "ping result: " << (ping_result ? "OK" : "FAIL")<<
434 0 : " (process " << getpid( ) << ", thread " <<
435 0 : std::this_thread::get_id() << ")" << std::endl;
436 0 : fflush(stderr);
437 : }
438 :
439 0 : plot_started_ = true;
440 :
441 0 : return true;
442 0 : }
443 :
444 :
445 0 : FlagAgentDisplay::plotter_t::plotter_t(std::shared_ptr<grpcFlagAgentState> state) :
446 0 : active_(false), response_svc(new grpcFlagAgentResponse(state)), plot_started_(false) {
447 0 : static const auto debug = getenv("GRPC_DEBUG");
448 :
449 0 : if ( debug ) {
450 : std::cerr << "attempting to start plotserver process " <<
451 0 : " (process " << getpid( ) << ", thread " <<
452 0 : std::this_thread::get_id() << ")" << std::endl;
453 0 : fflush(stderr);
454 : }
455 0 : std::string ps_path = get_casaplotserver_path( );
456 0 : if ( ps_path.size() > 0 ) {
457 : // sanity check on casaplotserver path...
458 : struct stat statbuf;
459 0 : if ( stat( ps_path.c_str( ), &statbuf ) < 0 ) {
460 : // file (or dir) does not exist... e.g.
461 : // >>>>>>registry available at 0.0.0.0:40939
462 : // stopping registry<<<<<<
463 0 : if ( debug ) {
464 : std::cerr << "could not find casaplotserver executable " <<
465 0 : " (process " << getpid( ) << ", thread " <<
466 0 : std::this_thread::get_id() << ")" << std::endl;
467 0 : fflush(stderr);
468 : }
469 : } else {
470 0 : if ( launch(ps_path) ) {
471 0 : active_ = true;
472 0 : } else if ( debug ) {
473 : std::cerr << "could not find casaplotserver executable " <<
474 0 : " (process " << getpid( ) << ", thread " <<
475 0 : std::this_thread::get_id() << ")" << std::endl;
476 0 : fflush(stderr);
477 : }
478 : }
479 0 : } else if ( debug ) {
480 : std::cerr << "could not find casaplotserver executable " <<
481 0 : " (process " << getpid( ) << ", thread " <<
482 0 : std::this_thread::get_id() << ")" << std::endl;
483 0 : fflush(stderr);
484 : }
485 :
486 0 : }
487 :
488 :
489 0 : FlagAgentDisplay::FlagAgentDisplay(FlagDataHandler *dh, Record config, Bool writePrivateFlagCube):
490 : FlagAgentBase(dh,config,ANTENNA_PAIRS_INTERACTIVE,writePrivateFlagCube),
491 0 : gui_state(new grpcFlagAgentState),
492 0 : dataplotter_p(NULL),reportplotter_p(NULL), pause_p(false),
493 0 : fieldId_p(-1), fieldName_p(""), scanStart_p(-1), scanEnd_p(-1), spwId_p(-1),
494 0 : nPolarizations_p(1), freqList_p(Vector<Double>()),
495 0 : dataDisplay_p(false), reportDisplay_p(false),reportFormat_p("screen"),
496 0 : stopAndExit_p(false),/* reportReturn_p(false),*/ showBandpass_p(false)
497 : {
498 : // Parse parameters and set base variables.
499 0 : setAgentParameters(config);
500 : // Request loading polarization map to FlagDataHandler
501 0 : flagDataHandler_p->setMapPolarizations(true);
502 : // Make the list of colours (these are almost all predefined ones for Qt.
503 : // Can add more later, based on RGB values.
504 0 : plotColours_p.resize(13);
505 0 : plotColours_p[0]="blue";
506 0 : plotColours_p[1]="red";
507 0 : plotColours_p[2]="green";
508 0 : plotColours_p[3]="cyan";
509 0 : plotColours_p[4]="darkGray";
510 0 : plotColours_p[5]="magenta";
511 0 : plotColours_p[6]="yellow";
512 0 : plotColours_p[7]="darkBlue";
513 0 : plotColours_p[8]="darkRed";
514 0 : plotColours_p[9]="darkGreen";
515 0 : plotColours_p[10]="darkCyan";
516 0 : plotColours_p[11]="black";
517 0 : plotColours_p[12]="darkMagenta";
518 :
519 0 : }
520 :
521 0 : bool FlagAgentDisplay::done( std::shared_ptr<FlagAgentDisplay::plotter_t> plotter ) {
522 : // send shutdown message to plotserver...
523 0 : static const auto debug = getenv("GRPC_DEBUG");
524 :
525 0 : if ( plotter && plotter->active( ) && plotter->plot_uri.size( ) > 0) {
526 0 : grpc::ClientContext context;
527 0 : ::google::protobuf::Empty req;
528 0 : ::google::protobuf::Empty resp;
529 0 : if ( debug ) {
530 : std::cerr << "attempting to shutdown plotserver [" <<
531 0 : plotter->plot_uri << "] " <<
532 0 : " (process " << getpid( ) << ", thread " <<
533 0 : std::this_thread::get_id() << ")" << std::endl;
534 0 : fflush(stderr);
535 : }
536 0 : auto shutdown = casatools::rpc::Shutdown::NewStub( grpc::CreateChannel( plotter->plot_uri, grpc::InsecureChannelCredentials( ) ) );
537 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
538 0 : context.set_deadline(deadline);
539 0 : shutdown->now( &context, req, &resp );
540 :
541 : // wait on plotserver to exit...
542 : int status;
543 0 : pid_t w = waitpid( plotter->pid, &status, WUNTRACED | WCONTINUED );
544 0 : if ( w == -1 ){
545 0 : if ( debug ) {
546 : std::cerr << "plotserver waitpid failed " <<
547 0 : " (process " << getpid( ) << ", thread " <<
548 0 : std::this_thread::get_id() << ")" << std::endl;
549 0 : fflush(stderr);
550 : }
551 : // waitpid failed
552 0 : return false;
553 0 : } else if ( w == 0 ) {
554 0 : if ( debug ) {
555 : std::cerr << "plotserver process not found " <<
556 0 : " (process " << getpid( ) << ", thread " <<
557 0 : std::this_thread::get_id() << ")" << std::endl;
558 0 : fflush(stderr);
559 : }
560 0 : return false;
561 : } else {
562 0 : if ( debug ) {
563 0 : std::cerr << "plotserver process (" << w << ") exited, status fetched " <<
564 0 : " (process " << getpid( ) << ", thread " <<
565 0 : std::this_thread::get_id() << ")" << std::endl;
566 0 : fflush(stderr);
567 : }
568 0 : plotter->pid = 0;
569 0 : return true;
570 : }
571 0 : }
572 :
573 0 : plotter.reset( );
574 0 : return true;
575 : }
576 :
577 0 : int FlagAgentDisplay::create_panel( std::shared_ptr<plotter_t> plot, int parent, bool new_row ) {
578 0 : static const auto debug = getenv("GRPC_DEBUG");
579 0 : string zoomloc="";
580 0 : string legendloc="bottom";
581 0 : grpc::ClientContext context;
582 0 : ::rpc::gui::Id result;
583 0 : ::rpc::gui::NewPanel panel;
584 0 : panel.set_title("");
585 0 : panel.set_xlabel("");
586 0 : panel.set_ylabel("");
587 0 : panel.set_window_title("");
588 0 : *panel.mutable_size( ) = { };
589 0 : panel.set_legend(legendloc);
590 0 : panel.set_zoom(zoomloc);
591 0 : panel.set_with_panel(parent);
592 0 : panel.set_new_row(new_row);
593 0 : panel.set_hidden(false);
594 0 : if ( debug ) {
595 0 : std::cerr << (plot->active( ) ? "FlagAgentDisplay creating panel " : "FlagAgentDisplay create ERROR plot not active ") <<
596 0 : " (process " << getpid( ) << ", thread " <<
597 0 : std::this_thread::get_id() << ")" << std::endl;
598 0 : fflush(stderr);
599 : }
600 :
601 0 : if ( ! plot->active( ) ) return -1;
602 :
603 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
604 0 : context.set_deadline(deadline);
605 0 : ::grpc::Status st = plot->plot->panel(&context,panel,&result);
606 0 : bool stat = st.ok( );
607 0 : if ( debug ) {
608 0 : std::cerr << "panel creation " << (stat ? "SUCCEEDED " : "FAILED ") << (stat ? result.id( ) : -1) <<
609 0 : " (process " << getpid( ) << ", thread " <<
610 0 : std::this_thread::get_id() << ")" << std::endl;
611 0 : fflush(stderr);
612 : }
613 0 : return stat ? result.id( ) : -1;
614 0 : }
615 :
616 0 : void FlagAgentDisplay::erase( std::shared_ptr<plotter_t> plot, int panel ) {
617 0 : static const auto debug = getenv("GRPC_DEBUG");
618 0 : grpc::ClientContext context;
619 0 : ::google::protobuf::Empty resp;
620 0 : ::rpc::gui::Id id;
621 :
622 0 : if ( debug ) {
623 0 : std::cerr << (plot->active( ) ? "FlagAgentDisplay erase " : "FlagAgentDisplay erase ERROR plot not active ") <<
624 0 : " (process " << getpid( ) << ", thread " <<
625 0 : std::this_thread::get_id() << ")" << std::endl;
626 0 : fflush(stderr);
627 : }
628 :
629 0 : if ( ! plot->active( ) ) return;
630 :
631 0 : id.set_id(panel);
632 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
633 0 : context.set_deadline(deadline);
634 0 : plot->plot->erase(&context,id,&resp);
635 0 : }
636 :
637 0 : void FlagAgentDisplay::setlabel( std::shared_ptr<plotter_t> plot, int panel,
638 : std::string xlabel, std::string ylabel, std::string title ) {
639 0 : static const auto debug = getenv("GRPC_DEBUG");
640 0 : grpc::ClientContext context;
641 0 : ::google::protobuf::Empty resp;
642 0 : ::rpc::gui::Label label;
643 :
644 0 : if ( debug ) {
645 0 : std::cerr << (plot->active( ) ? "FlagAgentDisplay setlabel " : "FlagAgentDisplay setlabel ERROR plot not active ") <<
646 0 : " (process " << getpid( ) << ", thread " <<
647 0 : std::this_thread::get_id() << ")" << std::endl;
648 0 : fflush(stderr);
649 : }
650 :
651 0 : if ( ! plot->active( ) ) return;
652 :
653 0 : label.mutable_panel( )->set_id(panel);
654 0 : label.set_xlabel(xlabel);
655 0 : label.set_ylabel(ylabel);
656 0 : label.set_title(title);
657 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
658 0 : context.set_deadline(deadline);
659 0 : plot->plot->setlabel(&context,label,&resp);
660 0 : }
661 :
662 0 : int FlagAgentDisplay::create_dock( std::shared_ptr<plotter_t> plot, int panel, std::string xml ) {
663 0 : static const auto debug = getenv("GRPC_DEBUG");
664 0 : grpc::ClientContext context;
665 0 : ::rpc::gui::DockSpec spec;
666 0 : ::rpc::gui::Id result;
667 :
668 0 : if ( debug ) {
669 0 : std::cerr << (plot->active( ) ? "FlagAgentDisplay create_dock " : "FlagAgentDisplay create_dock ERROR plot not active ") <<
670 0 : " (process " << getpid( ) << ", thread " <<
671 0 : std::this_thread::get_id() << ")" << std::endl;
672 0 : fflush(stderr);
673 : }
674 :
675 0 : if ( ! plot->active( ) ) return -1;
676 :
677 0 : spec.set_file_or_xml(xml);
678 0 : spec.set_loc("bottom");
679 0 : spec.add_dockable("top");
680 0 : spec.mutable_panel( )->set_id(panel);
681 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
682 0 : context.set_deadline(deadline);
683 0 : plot->plot->loaddock(&context,spec,&result);
684 0 : return result.id( );
685 0 : }
686 :
687 0 : int FlagAgentDisplay::raster( std::shared_ptr<plotter_t> plot, int panel, const std::vector<float> &data, ssize_t sizex, ssize_t sizey ) {
688 0 : static const auto debug = getenv("GRPC_DEBUG");
689 0 : grpc::ClientContext context;
690 0 : ::rpc::gui::Id result;
691 0 : ::rpc::gui::NewRaster raster;
692 :
693 0 : if ( debug ) {
694 0 : std::cerr << (plot->active( ) ? "FlagAgentDisplay raster " : "FlagAgentDisplay raster ERROR plot not active ") <<
695 0 : " (process " << getpid( ) << ", thread " <<
696 0 : std::this_thread::get_id() << ")" << std::endl;
697 0 : fflush(stderr);
698 : }
699 :
700 0 : if ( ! plot->active( ) ) return -1;
701 :
702 0 : raster.mutable_panel( )->set_id(panel);
703 0 : *raster.mutable_matrix( ) = { data.begin( ), data.end( ) };
704 0 : raster.set_sizex(sizex);
705 0 : raster.set_sizey(sizey);
706 0 : raster.set_colormap("Hot Metal 1");
707 :
708 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
709 0 : context.set_deadline(deadline);
710 0 : plot->plot->raster(&context,raster,&result);
711 0 : return result.id( );
712 0 : }
713 :
714 0 : int FlagAgentDisplay::line( std::shared_ptr<plotter_t> plot, int panel, const std::vector<float> &xdata, const std::vector<float> &ydata, std::string color, std::string label ) {
715 0 : static const auto debug = getenv("GRPC_DEBUG");
716 0 : grpc::ClientContext context;
717 0 : ::rpc::gui::Id result;
718 0 : ::rpc::gui::NewLine line;
719 :
720 0 : if ( debug ) {
721 0 : std::cerr << (plot->active( ) ? "FlagAgentDisplay line " : "FlagAgentDisplay line ERROR plot not active ") <<
722 0 : " (process " << getpid( ) << ", thread " <<
723 0 : std::this_thread::get_id() << ")" << std::endl;
724 0 : fflush(stderr);
725 : }
726 :
727 0 : if ( ! plot->active( ) ) return -1;
728 :
729 0 : line.mutable_panel( )->set_id(panel);
730 0 : *line.mutable_x( ) = { xdata.begin( ), xdata.end( ) };
731 0 : *line.mutable_y( ) = { ydata.begin( ), ydata.end( ) };
732 0 : line.set_color(color);
733 0 : line.set_label(label);
734 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
735 0 : context.set_deadline(deadline);
736 0 : plot->plot->line(&context,line,&result);
737 0 : return result.id( );
738 0 : }
739 :
740 0 : int FlagAgentDisplay::scatter( std::shared_ptr<plotter_t> plot, int panel, const std::vector<float> &xdata,
741 : const std::vector<float> &ydata, std::string color, std::string label,
742 : std::string symbol, int symbol_size, int dot_size ) {
743 0 : static const auto debug = getenv("GRPC_DEBUG");
744 0 : grpc::ClientContext context;
745 0 : ::rpc::gui::Id result;
746 0 : ::rpc::gui::NewScatter scatter;
747 :
748 0 : if ( debug ) {
749 0 : std::cerr << (plot->active( ) ? "FlagAgentDisplay scatter " : "FlagAgentDisplay scatter ERROR plot not active ") <<
750 0 : " (process " << getpid( ) << ", thread " <<
751 0 : std::this_thread::get_id() << ")" << std::endl;
752 0 : fflush(stderr);
753 : }
754 :
755 0 : if ( ! plot->active( ) ) return -1;
756 :
757 0 : scatter.mutable_panel( )->set_id(panel);
758 0 : *scatter.mutable_x( ) = { xdata.begin( ), xdata.end( ) };
759 0 : *scatter.mutable_y( ) = { ydata.begin( ), ydata.end( ) };
760 0 : scatter.set_color(color);
761 0 : scatter.set_label(label);
762 0 : scatter.set_symbol(symbol);
763 0 : scatter.set_symbol_size(symbol_size);
764 0 : scatter.set_dot_size(dot_size);
765 0 : auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(TIMEOUT);
766 0 : context.set_deadline(deadline);
767 0 : plot->plot->scatter(&context,scatter,&result);
768 0 : return result.id( );
769 0 : }
770 :
771 0 : FlagAgentDisplay::~FlagAgentDisplay()
772 : {
773 0 : static const auto debug = getenv("GRPC_DEBUG");
774 0 : if ( debug ) {
775 : std::cerr << "FlagAgentDisplay dtor " <<
776 0 : " (process " << getpid( ) << ", thread " <<
777 0 : std::this_thread::get_id() << ")" << std::endl;
778 0 : fflush(stderr);
779 : }
780 :
781 : // Compiler automagically calls FlagAgentBase::~FlagAgentBase()
782 0 : if ( dataplotter_p != NULL ) {
783 0 : done(dataplotter_p);
784 0 : dataplotter_p=NULL;
785 : }
786 0 : if ( reportplotter_p != NULL ) {
787 0 : done(reportplotter_p);
788 0 : reportplotter_p=NULL;
789 : }
790 0 : }
791 :
792 0 : void FlagAgentDisplay::setAgentParameters(Record config)
793 : {
794 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
795 : int exists;
796 :
797 0 : exists = config.fieldNumber ("pause");
798 0 : if (exists >= 0)
799 : {
800 0 : if( config.type(exists) != TpBool )
801 : {
802 0 : throw( AipsError ( "Parameter 'pause' must be of type 'bool'" ) );
803 : }
804 :
805 0 : pause_p = config.asBool("pause");
806 : }
807 : else
808 : {
809 0 : pause_p = true;
810 : }
811 :
812 0 : *logger_p << LogIO::NORMAL << " pause is " << pause_p << LogIO::POST;
813 :
814 0 : exists = config.fieldNumber ("datadisplay");
815 0 : if (exists >= 0)
816 : {
817 0 : if( config.type(exists) != TpBool )
818 : {
819 0 : throw( AipsError ( "Parameter 'datadisplay' must be of type 'bool'" ) );
820 : }
821 :
822 0 : dataDisplay_p = config.asBool("datadisplay");
823 : }
824 : else
825 : {
826 0 : dataDisplay_p = false;
827 : }
828 :
829 0 : *logger_p << LogIO::NORMAL << " datadisplay is " << dataDisplay_p << LogIO::POST;
830 :
831 0 : exists = config.fieldNumber ("reportdisplay");
832 0 : if (exists >= 0)
833 : {
834 0 : if( config.type(exists) != TpBool )
835 : {
836 0 : throw( AipsError ( "Parameter 'reportdisplay' must be of type 'bool'" ) );
837 : }
838 :
839 0 : reportDisplay_p = config.asBool("reportdisplay");
840 : }
841 : else
842 : {
843 0 : reportDisplay_p = false;
844 : }
845 :
846 0 : *logger_p << LogIO::NORMAL << " reportdisplay is " << reportDisplay_p << LogIO::POST;
847 :
848 :
849 0 : exists = config.fieldNumber ("format");
850 0 : if (exists >= 0)
851 : {
852 0 : if( config.type(exists) != TpString )
853 : {
854 0 : throw( AipsError ( "Parameter 'format' must be of type 'bool'" ) );
855 : }
856 :
857 0 : reportFormat_p = config.asString("format");
858 0 : if( reportFormat_p != "screen" && reportFormat_p != "file")
859 : {
860 0 : throw( AipsError( "Unsupported report format : " + reportFormat_p + ". Supported formats are 'screen' and 'file'") );
861 : }
862 : }
863 : else
864 : {
865 0 : reportFormat_p = String("screen");
866 : }
867 :
868 0 : *logger_p << LogIO::NORMAL << " format is " << reportFormat_p << LogIO::POST;
869 :
870 0 : }
871 :
872 :
873 : void
874 0 : FlagAgentDisplay::preProcessBuffer(const vi::VisBuffer2 &visBuffer)
875 : {
876 :
877 0 : getChunkInfo(visBuffer);
878 :
879 0 : return;
880 : }
881 :
882 :
883 : void
884 0 : FlagAgentDisplay::iterateAntennaPairsInteractive(antennaPairMap *antennaPairMap_ptr)
885 : {
886 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
887 : // Check if the visibility expression is suitable for this spw
888 0 : if (!checkVisExpression(flagDataHandler_p->getPolarizationMap())) return;
889 :
890 : // Iterate through antenna pair map
891 0 : std::pair<Int,Int> antennaPair;
892 0 : antennaPairMapIterator myAntennaPairMapIterator;
893 0 : bool stepback=false;
894 0 : for (myAntennaPairMapIterator=antennaPairMap_ptr->begin(); myAntennaPairMapIterator != antennaPairMap_ptr->end(); ++myAntennaPairMapIterator)
895 : {
896 :
897 : // Check whether to skip the rest of this chunk or not
898 0 : if(gui_state->skipSpw_p != -1)
899 : {
900 0 : if(gui_state->skipSpw_p == spwId_p) {dataDisplay_p=false;} // Skip the rest of this SPW
901 : else {
902 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
903 0 : gui_state->skipSpw_p = -1;
904 0 : dataDisplay_p=true;
905 0 : } // Reached next SPW. Reset state
906 : }
907 0 : if(gui_state->skipField_p != -1)
908 : {
909 0 : if(gui_state->skipField_p == fieldId_p) {dataDisplay_p=false;} // Skip the rest of this Field
910 : else {
911 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
912 0 : gui_state->skipField_p = -1;
913 0 : dataDisplay_p=true;
914 0 : } // Reached next Field. Reset state
915 : }
916 0 : if(gui_state->skipScan_p != -1)
917 : {
918 0 : if(gui_state->skipScan_p == scanEnd_p) {dataDisplay_p=false;} // Skip the rest of this Scan
919 : else {
920 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
921 0 : gui_state->skipScan_p = -1;
922 0 : dataDisplay_p=true;
923 0 : } // Reached next Scan. Reset state
924 : }
925 :
926 :
927 : // Display this baseline
928 0 : if(dataDisplay_p)
929 : {
930 :
931 : // If choice from previous plot was to go backwards in baseline.
932 0 : if(stepback)
933 : {
934 : // Go to previous baseline (decrement by 2)
935 0 : if( myAntennaPairMapIterator != antennaPairMap_ptr->begin() )
936 0 : -- myAntennaPairMapIterator;
937 0 : if( myAntennaPairMapIterator != antennaPairMap_ptr->begin() )
938 0 : -- myAntennaPairMapIterator;
939 :
940 : // If antenna constraints exist, keep going back until first match is found.
941 : // If not found, stay on current baseline (continue)
942 0 : if( gui_state->userFixA1_p != "" || gui_state->userFixA2_p != "" )
943 : {
944 0 : antennaPairMapIterator tempIterator;
945 0 : bool found=false;
946 0 : for(tempIterator = myAntennaPairMapIterator; tempIterator != antennaPairMap_ptr->begin() ; --tempIterator )
947 : {
948 0 : if( ! skipBaseline(tempIterator->first) ) {found=true; break;}
949 : }
950 0 : if(found) // Jump to this antenna pair
951 : {
952 0 : myAntennaPairMapIterator = tempIterator;
953 : }
954 : else
955 : {
956 0 : *logger_p << "No Previous baseline in this chunk with Ant1 : "
957 0 : << ( (gui_state->userFixA1_p != "") ? gui_state->userFixA1_p : "any" )
958 : << " and Ant2 : "
959 0 : << ( (gui_state->userFixA2_p != "") ? gui_state->userFixA2_p : "any" )
960 0 : << LogIO::POST;
961 :
962 : // Stay on current baseline
963 0 : if( myAntennaPairMapIterator != antennaPairMap_ptr->end() )
964 0 : ++myAntennaPairMapIterator;
965 : }
966 : }
967 :
968 : // Reset state
969 0 : stepback=false;
970 : }
971 :
972 : // Get antenna pair from map
973 0 : antennaPair = myAntennaPairMapIterator->first;
974 :
975 : // Check whether or not to display this baseline (for going in the forward direction)
976 0 : if( skipBaseline(antennaPair) ) continue;
977 :
978 : // Process antenna pair
979 0 : processAntennaPair(antennaPair.first,antennaPair.second);
980 :
981 : // If Plot window is visible, and, if asked for, get and react to user-choices.
982 0 : if(pause_p==true)
983 : {
984 :
985 : // Wait for User Input
986 0 : getUserInput( ); // Fills in userChoice_p. userfix
987 :
988 : // React to user-input
989 0 : if(gui_state->userChoice_p=="Quit")
990 : {
991 0 : dataDisplay_p = false;
992 0 : stopAndExit_p = true;
993 0 : *logger_p << "Exiting flagger" << LogIO::POST;
994 0 : if ( dataplotter_p != NULL ) {
995 0 : done(dataplotter_p);
996 0 : dataplotter_p=NULL;
997 : }
998 0 : flagDataHandler_p->stopIteration();
999 0 : return ;
1000 : }
1001 0 : else if(gui_state->userChoice_p=="StopDisplay")
1002 : {
1003 0 : dataDisplay_p = false;
1004 0 : *logger_p << "Stopping display. Continuing flagging." << LogIO::POST;
1005 0 : if ( dataplotter_p != NULL ) {
1006 0 : done(dataplotter_p);
1007 0 : dataplotter_p=NULL;
1008 : }
1009 : }
1010 0 : else if(gui_state->userChoice_p=="PrevBaseline")
1011 : {
1012 0 : if( myAntennaPairMapIterator==antennaPairMap_ptr->begin() )
1013 0 : *logger_p << "Already on first baseline..." << LogIO::POST;
1014 0 : stepback=true;
1015 : }
1016 0 : else if(gui_state->userChoice_p=="NextScan")
1017 : {
1018 : //*logger_p << "Next Scan " << LogIO::POST;
1019 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1020 0 : gui_state->skipScan_p = scanEnd_p;
1021 0 : }
1022 0 : else if(gui_state->userChoice_p=="NextSpw")
1023 : {
1024 : //*logger_p << "Next SPW " << LogIO::POST;
1025 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1026 0 : gui_state->skipSpw_p = spwId_p;
1027 0 : }
1028 0 : else if(gui_state->userChoice_p=="NextField")
1029 : {
1030 : //*logger_p << "Next Field " << LogIO::POST;
1031 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1032 0 : gui_state->skipField_p = fieldId_p;
1033 0 : }
1034 0 : else if(gui_state->userChoice_p=="Continue")
1035 : {
1036 : //*logger_p << "Next chunk " << LogIO::POST; // Right now, a chunk is one baseline !
1037 0 : return;
1038 : }
1039 :
1040 : }// end if pause=true
1041 :
1042 : }// if dataDisplay_p
1043 :
1044 : }// end antennaMapIterator
1045 :
1046 0 : return;
1047 : }// end iterateAntennaPairsInteractive
1048 :
1049 :
1050 : Bool
1051 0 : FlagAgentDisplay::skipBaseline(std::pair<Int,Int> antennaPair)
1052 : {
1053 0 : std::string antenna1Name = flagDataHandler_p->antennaNames_p->operator()(antennaPair.first);
1054 0 : std::string antenna2Name = flagDataHandler_p->antennaNames_p->operator()(antennaPair.second);
1055 : // if(userFixA2_p != "") cout << "*********** userfixa2 : " << userFixA2_p << " thisant : " << antenna1Name << " && " << antenna2Name << LogIO::POST;
1056 0 : return ( (gui_state->userFixA1_p != "" && gui_state->userFixA1_p != antenna1Name) ||
1057 0 : (gui_state->userFixA2_p != "" && gui_state->userFixA2_p != antenna2Name) ) ;
1058 0 : }
1059 :
1060 : bool
1061 0 : FlagAgentDisplay::computeAntennaPairFlags(const vi::VisBuffer2 &visBuffer,
1062 : VisMapper &visibilities,FlagMapper &flags,Int antenna1,Int antenna2,
1063 : vector<uInt> &/*rows*/)
1064 : {
1065 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1066 : // Gather shapes
1067 0 : IPosition flagCubeShape = visibilities.shape();
1068 0 : uInt nChannels = flagCubeShape(0);
1069 0 : uInt nTimes = flagCubeShape(1);
1070 :
1071 : // Read antenna names for the current baseline
1072 0 : String antenna1Name = flagDataHandler_p->antennaNames_p->operator()(antenna1);
1073 0 : String antenna2Name = flagDataHandler_p->antennaNames_p->operator()(antenna2);
1074 0 : String baselineName = antenna1Name + "&&" + antenna2Name;
1075 : {
1076 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1077 0 : gui_state->antenna1_p = antenna1Name;
1078 0 : gui_state->antenna2_p = antenna2Name;
1079 0 : }
1080 :
1081 0 : String scanRange = (scanStart_p!=scanEnd_p)?String::toString(scanStart_p)+"~"+String::toString(scanEnd_p) : String::toString(scanStart_p);
1082 0 : String spwName = String::toString(visBuffer.spectralWindows()(0));
1083 :
1084 : // Get Frequency List
1085 0 : freqList_p.resize(nChannels);
1086 0 : for(uInt ch=0;ch<nChannels;ch++) freqList_p[ch]=(Double)ch;
1087 :
1088 :
1089 : /*
1090 : // Read current Field name, SPW id, and correlation string from visBuffer Info.
1091 : uInt fieldId_p = visBuffer.fieldId();
1092 : String fieldName = visBuffer.msColumns().field().name().getColumn()[fieldId_p];
1093 : String spwName = String::toString(visBuffer.spectralWindow());
1094 : Int scanstart = visBuffer.scan()[0];
1095 : int scanend = visBuffer.scan()[ (visBuffer.scan().nelements())-1 ];
1096 : String scanRange = (scanstart!=scanend)?String::toString(scanstart)+"~"+String::toString(scanend) : String::toString(scanstart);
1097 : */
1098 :
1099 : // Get Polarization Maps
1100 : /*
1101 : Vector<uInt> polarizations = flags.getSelectedCorrelations();
1102 : nPolarizations_p = polarizations.size();
1103 : polarizationIndexMap *polMap = flagDataHandler_p->getPolarizationIndexMap();
1104 : Vector<String> corrTypes(nPolarizations_p);
1105 : for(uInt pol=0;pol<nPolarizations_p;pol++)
1106 : corrTypes[pol] = (*polMap)[polarizations[pol]];
1107 : */
1108 :
1109 : // Get Polarization Maps
1110 : // jagonzal: Migrated to new implementation of multiple expressions handling
1111 0 : vector<string> corrTypes = visibilities.getSelectedCorrelationStrings();
1112 0 : nPolarizations_p = corrTypes.size();
1113 :
1114 : ///cout << "Selected Correlations : " << polarizations << LogIO::POST;
1115 :
1116 : // Print where we are...
1117 : // *logger_p << LogIO::NORMAL << " Baseline : " << baselineName << " Field : " << fieldName_p << " Spw : " << spwName << " nChan : " << nChannels << " nPol : " << nPolarizations_p << " nTime : " << nTimes << LogIO::POST;
1118 :
1119 : // Build the Plot Window for the first time
1120 0 : if(dataDisplay_p && dataplotter_p==NULL) buildDataPlotWindow();
1121 :
1122 : // Adding this block of code as a fix for CAS-4052.
1123 : // J.G. : If you find a better way to do this, please change this...
1124 0 : if(dataDisplay_p==true && dataplotter_p!=NULL)
1125 : {
1126 : Int nrows;
1127 0 : if(showBandpass_p==true) nrows=3;
1128 0 : else nrows=2;
1129 :
1130 0 : if(panels_p.size() != nPolarizations_p*nrows)
1131 : {
1132 : //cout << "Wrong number of panels !" << endl;
1133 0 : done(dataplotter_p);
1134 0 : dataplotter_p = NULL;
1135 0 : buildDataPlotWindow();
1136 : }
1137 : }
1138 :
1139 : // Initialize Plot Arrays and other vars
1140 0 : Float runningsum=0, runningflag=0,runningpreflag=0;
1141 0 : Vector<Float> vecflagdat(0), vecdispdat(0);
1142 0 : Vector<Float> origspectrum(0), flagspectrum(0), precountspec(0), countspec(0);
1143 0 : if(dataDisplay_p)
1144 : {
1145 0 : vecflagdat.resize(nChannels * nTimes); vecdispdat.resize(nChannels * nTimes);
1146 0 : origspectrum.resize(nChannels); flagspectrum.resize(nChannels);
1147 0 : precountspec.resize(nChannels); countspec.resize(nChannels);
1148 : }
1149 :
1150 0 : if(dataDisplay_p)
1151 : {
1152 : // Make and send plots for each polarization
1153 0 : for(int pl=0;pl<(int) nPolarizations_p;pl++) // Start Correlation Loop
1154 : {
1155 0 : runningsum=0; runningflag=0; runningpreflag=0;
1156 0 : origspectrum=0.0; flagspectrum=0.0; precountspec=0.0; countspec=0.0;
1157 0 : for(int ch=0;ch<(int) nChannels;ch++) // Start Channel Loop
1158 : {
1159 0 : for(uInt tm=0;tm<nTimes;tm++) // Start Time Loop
1160 : {
1161 : // UUU FOR TEST ONLY -- Later, enable additional ManualFlagAgent in the tFlagAgentDisplay
1162 : /////if(ch>10 && ch<20) flags.applyFlag(ch,tm);
1163 :
1164 0 : vecdispdat( ch*nTimes + tm ) = visibilities(pl,ch,tm) * ( ! flags.getOriginalFlags(pl,ch,tm) );
1165 0 : vecflagdat( ch*nTimes + tm ) = visibilities(pl,ch,tm) * ( ! flags.getModifiedFlags(pl,ch,tm) );
1166 :
1167 0 : origspectrum[ch] += visibilities(pl,ch,tm) * ( ! flags.getOriginalFlags(pl,ch,tm) );
1168 0 : flagspectrum[ch] += visibilities(pl,ch,tm) * ( ! flags.getModifiedFlags(pl,ch,tm) );
1169 :
1170 0 : precountspec[ch] += ( ! flags.getOriginalFlags(pl,ch,tm) );
1171 0 : countspec[ch] += ( ! flags.getModifiedFlags(pl,ch,tm) );
1172 :
1173 0 : runningsum += visibilities(pl,ch,tm);
1174 0 : runningflag += (Float)(flags.getModifiedFlags(pl,ch,tm));
1175 0 : runningpreflag += (Float)(flags.getOriginalFlags(pl,ch,tm));
1176 :
1177 : }// End Time Loop
1178 : }//End Channel Loop
1179 :
1180 : // Make the Labels
1181 0 : stringstream ostr1,ostr2;
1182 0 : ostr1 << "(" << fieldId_p << ") " << fieldName_p << " [scan:" << scanRange << "]\n[spw:" << spwName << "] " << baselineName << " ( " << corrTypes[pl] << " )";
1183 0 : ostr2 << fixed;
1184 0 : ostr2.precision(1);
1185 0 : ostr2 << " flag:" << 100 * runningflag/(nChannels*nTimes) << "% (pre-flag:" << 100 * runningpreflag/(nChannels*nTimes) << "%)";
1186 :
1187 : //*logger_p << "[" << corrTypes[pl] << "]:" << 100 * runningflag/(nChannels*nTimes) << "%(" << 100 * runningpreflag/(nChannels*nTimes) << "%) ";
1188 :
1189 : // Make the Before/After Raster Plots
1190 0 : DisplayRaster(nChannels,nTimes,vecdispdat,panels_p[pl]);
1191 0 : setlabel( dataplotter_p, panels_p[pl], " ", pl?" ":"Time", ostr1.str() );
1192 0 : DisplayRaster(nChannels,nTimes,vecflagdat,panels_p[pl+nPolarizations_p]);
1193 0 : setlabel( dataplotter_p, panels_p[pl+nPolarizations_p], "Frequency", pl?" ":"Time", ostr2.str() );
1194 :
1195 0 : if(showBandpass_p==true)
1196 : {
1197 :
1198 : // Make the Before/After bandpass plots
1199 0 : for(uInt ch=0;ch<nChannels;ch++)
1200 : {
1201 0 : if(precountspec[ch]==0) {origspectrum[ch]=0.0; precountspec[ch]=1.0;}
1202 0 : if(countspec[ch]==0) {flagspectrum[ch]=0.0; countspec[ch]=1.0;}
1203 : }
1204 :
1205 0 : origspectrum = (origspectrum/precountspec);
1206 0 : flagspectrum = (flagspectrum/countspec);
1207 0 : AlwaysAssert( freqList_p.nelements()==nChannels , AipsError);
1208 :
1209 0 : DisplayLine( nChannels, freqList_p, origspectrum, String("before:")+String(corrTypes[pl]),
1210 0 : String("red"), false, panels_p[pl+(2*nPolarizations_p)] );
1211 0 : DisplayScatter( nChannels, freqList_p, flagspectrum, String("after:")+String(corrTypes[pl]),
1212 0 : String("blue"), true, panels_p[pl+(2*nPolarizations_p)] );
1213 :
1214 : //// TODO : Can I query the tfcrop agent for a "view" to overlay here.
1215 : // If available, get a plot from the agents
1216 : /*
1217 : for (uInt fmeth=0; fmeth<flagmethods.nelements(); fmeth++)
1218 : {
1219 : if(flagmethods[fmeth]->getMonitorSpectrum(flagspectrum,pl,bs))
1220 : {
1221 : // flagspectrum = log10(flagspectrum);
1222 : DisplayLine(nChannels, freqlist_p, flagspectrum, flagmethods[fmeth]->methodName(),
1223 : String("green"), true, panels_p[pl+(2*nPolarizations_p)].getInt());
1224 : }
1225 : }
1226 : */
1227 : }// end of if (showBandPass_p)
1228 :
1229 0 : }//End Correlation Loop
1230 :
1231 : //*logger_p << LogIO::POST;
1232 :
1233 : }// end if dataDisplay_p
1234 :
1235 0 : return false;
1236 0 : }// end computeAntennaPairFlags
1237 :
1238 : //----------------------------------------------------------------------------------------------------------
1239 :
1240 : void
1241 0 : FlagAgentDisplay::getChunkInfo(const vi::VisBuffer2 &visBuffer)
1242 : {
1243 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1244 : // Read current Field name, SPW id, and scan info.
1245 0 : fieldId_p = visBuffer.fieldId()(0);
1246 0 : fieldName_p = flagDataHandler_p->fieldNames_p->operator()(fieldId_p);
1247 0 : spwId_p = visBuffer.spectralWindows()(0);
1248 0 : scanStart_p = visBuffer.scan()[0];
1249 0 : scanEnd_p = visBuffer.scan()[ (visBuffer.scan().nelements())-1 ];
1250 :
1251 0 : *logger_p << LogIO::NORMAL << "FlagAgentDisplay::" << __FUNCTION__ << " Field : " << fieldId_p << " , " << fieldName_p << " Spw : " << spwId_p << " Scan : " << scanStart_p << " : " << scanEnd_p << LogIO::POST;
1252 0 : }
1253 :
1254 : //----------------------------------------------------------------------------------------------------------
1255 :
1256 : FlagReport
1257 0 : FlagAgentDisplay::getReport()
1258 : {
1259 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1260 :
1261 : // FlagReport dispRep("plot",agentName_p);
1262 :
1263 : // Make empty list
1264 0 : FlagReport dispRep("list");
1265 :
1266 : /*
1267 :
1268 : // Make sample arrays/vectors
1269 : Int N=10;
1270 : Array<Float> sample( IPosition(2, N, N) );
1271 : sample = 0.0;
1272 : sample( IPosition(2,N/2,N/2)) = 1.0;
1273 : Vector<Float> xdata( N ), ydata( N ), error ( N );
1274 : for(Int i=0;i<N;i++) {xdata[i]=i;}
1275 : ydata = 1.0;
1276 :
1277 : // (1) Make a raster plot. Only one set of data is allowed here.
1278 : FlagReport subRep0 = FlagReport("plotraster",agentName_p,"example raster", "xaxis", "yaxis");
1279 : subRep0.addData(sample); // add 2D data
1280 :
1281 : // Add this raster FlagReport to the list.
1282 : dispRep.addReport( subRep0 );
1283 :
1284 : // (2) Make a line plot. Can give multiple lines to overlay on the same panel.
1285 : FlagReport subRep1 = FlagReport("plotpoints",agentName_p,"example line", "xaxis", "yaxis");
1286 : subRep1.addData("line", xdata,ydata,"",Vector<Float>(),"line 1"); // add first set of line data
1287 : ydata[N/2]=2.0;
1288 : subRep1.addData("scatter", xdata,ydata,"",Vector<Float>(),"scatter 2"); // add second set of line data to overlay
1289 :
1290 : // Add this line FlagReport to the list
1291 : dispRep.addReport( subRep1 );
1292 :
1293 : // (3) Make an overlay of a line with errorbar, scatter with errorbar, and scatter with circle
1294 : FlagReport subRep2 = FlagReport("plotpoints",agentName_p,"example line", "xaxis", "yaxis");
1295 : for(Int i=0;i<N;i++) {error[i]=i;}
1296 : subRep2.addData("line", xdata,ydata,"bar",error,"line+bar"); // add first set of line data, with errorbars
1297 : for(Int i=0;i<N;i++) {xdata[i] += 0.3; error[i]=i; ydata[i]+=2.0;}
1298 : subRep2.addData("scatter", xdata, ydata,"bar",error,"scatter+bar"); // add second set of scatter data to overlay, with error bars
1299 : for(Int i=0;i<N;i++) {xdata[i] += 0.3; error[i]=i*10; ydata[i]+=2.0;}
1300 : subRep2.addData("scatter", xdata, ydata,"circle",error,"scatter+circle"); // add third set, scatter data with circles.
1301 :
1302 : // Add this line FlagReport to the list
1303 : dispRep.addReport( subRep2 );
1304 :
1305 : if( ! dispRep.verifyFields() )
1306 : cout << "Problem ! " << endl;
1307 :
1308 :
1309 : */
1310 :
1311 0 : return dispRep;
1312 : }// end of getReport()
1313 :
1314 : //----------------------------------------------------------------------------------------------------------
1315 : // Go through the list of reports and make plots
1316 : Bool
1317 0 : FlagAgentDisplay::displayReports(FlagReport &combinedReport)
1318 : {
1319 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1320 :
1321 0 : if(reportDisplay_p && !stopAndExit_p)
1322 : {
1323 0 : Int nReports = combinedReport.nReport();
1324 :
1325 0 : if( dataplotter_p != NULL ) {
1326 0 : done(dataplotter_p);
1327 0 : dataplotter_p = NULL;
1328 : }
1329 0 : if(nReports>0 && reportplotter_p==NULL) buildReportPlotWindow();
1330 :
1331 0 : Bool stepback=false;
1332 :
1333 0 : for (Int reportid=0; reportid<nReports; reportid++)
1334 : {
1335 0 : String agentName, title, xlabel, ylabel;
1336 0 : FlagReport oneRep;
1337 :
1338 0 : if(stepback==true)
1339 : {
1340 : // Go back until a valid one is found.
1341 0 : Int previd=-1;
1342 0 : for( Int rep=reportid-1; rep>=0; --rep)
1343 : {
1344 0 : Bool valid = combinedReport.accessReport(rep,oneRep);
1345 0 : if(valid)
1346 : {
1347 0 : String type = oneRep.reportType();
1348 0 : if( type=="plotraster" || type=="plotpoints" )
1349 : {
1350 0 : previd=rep; break;
1351 : }
1352 0 : }
1353 : }
1354 :
1355 0 : if(previd==-1)
1356 : {
1357 0 : *logger_p << "Already on first plot" << LogIO::POST;
1358 0 : reportid=0;
1359 : }
1360 : else
1361 : {
1362 0 : reportid = previd;
1363 : }
1364 :
1365 0 : stepback=false;
1366 : }
1367 :
1368 :
1369 0 : Bool valid = combinedReport.accessReport(reportid,oneRep);
1370 0 : if(valid)
1371 : {
1372 0 : oneRep.get( RecordFieldId("name") , agentName );
1373 0 : String type = oneRep.reportType();
1374 :
1375 0 : if( type=="plotraster" || type=="plotpoints" )
1376 : {
1377 :
1378 0 : *logger_p << reportid << " : " << type << " with " << oneRep.nData() << " layer(s) " << " from " << agentName << LogIO::POST;
1379 :
1380 0 : if( type == "plotraster" )
1381 : {
1382 0 : oneRep.get( RecordFieldId("title") , title );
1383 0 : oneRep.get( RecordFieldId("xlabel") , xlabel );
1384 0 : oneRep.get( RecordFieldId("ylabel") , ylabel );
1385 :
1386 0 : Array<Float> data;
1387 0 : oneRep.get( RecordFieldId("data"+String::toString(0)) , data );
1388 :
1389 0 : std::vector<float> flatdata(data.begin(),data.end());
1390 :
1391 0 : erase( reportplotter_p, report_panels_p[0] );
1392 0 : raster( reportplotter_p, report_panels_p[0], flatdata, data.shape()[0], data.shape()[1] );
1393 0 : setlabel( reportplotter_p, report_panels_p[0], xlabel, ylabel, title );
1394 :
1395 0 : }
1396 0 : else if( type == "plotpoints")
1397 : {
1398 0 : oneRep.get( RecordFieldId("title") , title );
1399 0 : oneRep.get( RecordFieldId("xlabel") , xlabel );
1400 0 : oneRep.get( RecordFieldId("ylabel") , ylabel );
1401 :
1402 0 : erase( reportplotter_p, report_panels_p[0] );
1403 :
1404 0 : Int ndata = oneRep.nData();
1405 0 : for(Int datid=0;datid<ndata;datid++)
1406 : {
1407 0 : Vector<Float> xdata,ydata,error;
1408 0 : String legendlabel,plottype="line",errortype="";
1409 0 : oneRep.get( RecordFieldId("xdata"+String::toString(datid)) , xdata );
1410 0 : oneRep.get( RecordFieldId("ydata"+String::toString(datid)) , ydata );
1411 0 : oneRep.get( RecordFieldId("label"+String::toString(datid)) , legendlabel );
1412 0 : oneRep.get( RecordFieldId("plottype"+String::toString(datid)) , plottype );
1413 :
1414 : ///reportplotter_p->line(dbus::af(xdata), dbus::af(ydata),(datid%2)?String("red"):String("blue"),legendlabel, report_panels_p[0].getInt());
1415 :
1416 0 : if ( oneRep.isDefined( "error"+String::toString(datid) ) )
1417 : {
1418 0 : oneRep.get( RecordFieldId("error"+String::toString(datid)) , error );
1419 0 : oneRep.get( RecordFieldId("errortype"+String::toString(datid)) , errortype );
1420 : }
1421 :
1422 0 : DisplayLineScatterError(reportplotter_p , plottype, xdata, ydata, errortype, error, legendlabel, plotColours_p[datid%plotColours_p.nelements()], report_panels_p[0] );
1423 : /// (datid%2)?String("red"):String("blue")
1424 0 : }// end of for datid
1425 :
1426 0 : setlabel( reportplotter_p, report_panels_p[0], xlabel, ylabel, title );
1427 :
1428 : }// end of plotpoints
1429 : else
1430 : {
1431 0 : *logger_p << "NO Display for : " << reportid << " : " << agentName << LogIO::POST;
1432 : }
1433 :
1434 0 : getReportUserInput();
1435 :
1436 : // React to user-input
1437 0 : if(gui_state->userChoice_p=="Quit")
1438 : {
1439 0 : dataDisplay_p = false;
1440 0 : stopAndExit_p = true;
1441 : //*logger_p << "Exiting flagger" << LogIO::POST;
1442 0 : if( reportplotter_p != NULL ) {
1443 0 : done(reportplotter_p);
1444 0 : reportplotter_p = NULL;
1445 : }
1446 0 : return true;
1447 : }
1448 0 : else if(gui_state->userChoice_p=="Prev")
1449 : {
1450 : //*logger_p << "Prev Plot" << LogIO::POST;
1451 0 : if( reportid==0 )
1452 0 : *logger_p << "Already on first plot..." << LogIO::POST;
1453 : else
1454 0 : --reportid;
1455 0 : stepback=true;
1456 : }
1457 0 : else if(gui_state->userChoice_p=="Continue" || gui_state->userChoice_p=="Next")
1458 : {
1459 : //*logger_p << "Next Plot " << LogIO::POST;
1460 0 : if( reportid==nReports-1 )
1461 : {
1462 0 : *logger_p << "Already on last plot..." << LogIO::POST;
1463 0 : --reportid;
1464 : }
1465 : }
1466 :
1467 : }// if valid plot type
1468 : else
1469 : {
1470 : //*logger_p << "No plot for Report : " << reportid << LogIO::POST;
1471 0 : *logger_p << reportid << " : No plot for report from " << agentName << LogIO::POST;
1472 :
1473 : }
1474 0 : }// if valid plot record.
1475 : else
1476 : {
1477 0 : *logger_p << LogIO::WARN << "Invalid Plot Record for : " << reportid << LogIO::POST;
1478 : }
1479 :
1480 0 : }// end of for-report-in-combinedReport
1481 :
1482 0 : }// end of reportDisplay_p==true
1483 : else
1484 : {
1485 0 : *logger_p << "Report Displays are turned OFF " << LogIO::POST;
1486 : }
1487 0 : return true;
1488 : } // end of displayReports()
1489 :
1490 : /***********************************************************************/
1491 : /****************** Plot Functions ******************************/
1492 : /***********************************************************************/
1493 :
1494 : // Note : By default, only two rows of plots are created.
1495 : // The third row, for bandpass plots (before and after) are turned off
1496 : // by the private variable 'showBandPass_p'. This can be later
1497 : // enabled when we get per-chunk 'extra info' displays/reports from
1498 : // the agents. Right now, it's redundant info, and takes up too much
1499 : // space on small laptop screens.
1500 0 : Bool FlagAgentDisplay::buildDataPlotWindow()
1501 : {
1502 :
1503 0 : setDataLayout();
1504 0 : AlwaysAssert( dock_xml_p != NULL , AipsError );
1505 :
1506 0 : dataplotter_p.reset(new plotter_t(gui_state));
1507 :
1508 : Int nrows;
1509 0 : if(showBandpass_p==true) nrows=3;
1510 0 : else nrows=2;
1511 0 : panels_p.resize(nPolarizations_p*nrows);
1512 0 : string zoomloc="";
1513 0 : string legendloc="bottom";
1514 :
1515 : // First row : Data with no flags
1516 0 : panels_p[0] = create_panel(dataplotter_p,0,false);
1517 :
1518 0 : if(nPolarizations_p>1)
1519 : {
1520 0 : for(Int i=1;i<(int) nPolarizations_p;i++)
1521 : {
1522 0 : panels_p[i] = create_panel(dataplotter_p,panels_p[i-1],false);
1523 : }
1524 : }
1525 :
1526 :
1527 : // Second row : Data with flags
1528 0 : panels_p[nPolarizations_p] = create_panel(dataplotter_p,panels_p[0],true);
1529 0 : if(nPolarizations_p>1)
1530 : {
1531 0 : for(int i=static_cast<int>(nPolarizations_p)+1;i<2*static_cast<int>(nPolarizations_p);i++)
1532 : {
1533 0 : panels_p[i] = create_panel(dataplotter_p,panels_p[i-1],false);
1534 : }
1535 : }
1536 :
1537 : // Third row : Average Bandpass
1538 0 : if(showBandpass_p==true)
1539 : {
1540 0 : panels_p[2*nPolarizations_p] = create_panel(dataplotter_p,panels_p[0],true);
1541 :
1542 0 : if(nPolarizations_p>1)
1543 : {
1544 0 : for(int i=2* static_cast<int>(nPolarizations_p)+1;i<3*static_cast<int>(nPolarizations_p);i++)
1545 : {
1546 0 : panels_p[i] = create_panel(dataplotter_p,panels_p[i-1],false);
1547 : }
1548 : }
1549 : }// if showbandpass
1550 :
1551 : /*
1552 : // Misc panel
1553 : panels_p[8] = dataplotter_p->panel( "BandPass", "Frequency", "Amp", "",
1554 : std::vector<int>( ),legendloc,zoomloc, panels_p[3].getInt(),false,false);
1555 :
1556 : // Dummy panel
1557 : panels_p[9] = dataplotter_p->panel( "---", "----", "---", "",
1558 : std::vector<int>( ),legendloc,zoomloc, panels_p[7].getInt(),false,false);
1559 : */
1560 :
1561 0 : create_dock(dataplotter_p, panels_p[0],dock_xml_p);
1562 0 : return true;
1563 :
1564 0 : }// end buildDataPlotWindow
1565 :
1566 :
1567 0 : Bool FlagAgentDisplay::buildReportPlotWindow()
1568 : {
1569 :
1570 0 : setReportLayout();
1571 0 : AlwaysAssert( report_dock_xml_p != NULL , AipsError );
1572 :
1573 0 : reportplotter_p.reset(new plotter_t(gui_state));
1574 :
1575 0 : report_panels_p.resize(1);
1576 0 : string zoomloc="";
1577 0 : string legendloc="bottom";
1578 0 : report_panels_p[0] = create_panel(reportplotter_p,0,false);
1579 :
1580 0 : create_dock( reportplotter_p, report_panels_p[0], report_dock_xml_p );
1581 0 : return true;
1582 :
1583 0 : }// end buildReportPlotWindow
1584 :
1585 :
1586 :
1587 0 : void FlagAgentDisplay::getUserInput( ) {
1588 :
1589 0 : static const auto debug = getenv("GRPC_DEBUG");
1590 0 : if ( debug ) {
1591 0 : std::cerr << ( active( ) ?
1592 : "FlagAgentDisplay getUserInput " :
1593 : "FlagAgentDisplay getUserInput ERROR no active GUIs " ) <<
1594 0 : " (process " << getpid( ) << ", thread " <<
1595 0 : std::this_thread::get_id() << ")" << std::endl;
1596 0 : fflush(stderr);
1597 : }
1598 :
1599 0 : if ( ! active( ) ) return;
1600 :
1601 0 : if ( gui_state->input_received ) {
1602 : // GUI input received while this thread was preoccupied...
1603 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1604 0 : gui_state->input_received = false;
1605 0 : return;
1606 0 : } else {
1607 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1608 0 : gui_state->userChoice_p = "Continue";
1609 0 : gui_state->output = std::promise<bool>( );
1610 0 : gui_state->input_needed = true;
1611 0 : }
1612 :
1613 0 : auto fut = gui_state->output.get_future();
1614 0 : fut.get( );
1615 : {
1616 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1617 0 : gui_state->input_received = false;
1618 0 : }
1619 0 : }
1620 :
1621 :
1622 :
1623 0 : void FlagAgentDisplay :: getReportUserInput() {
1624 :
1625 0 : static const auto debug = getenv("GRPC_DEBUG");
1626 0 : if ( debug ) {
1627 0 : std::cerr << ( active( ) ?
1628 : "FlagAgentDisplay getReportUserInput " :
1629 : "FlagAgentDisplay getReportUserInput ERROR no active GUIs " ) <<
1630 0 : " (process " << getpid( ) << ", thread " <<
1631 0 : std::this_thread::get_id() << ")" << std::endl;
1632 0 : fflush(stderr);
1633 : }
1634 :
1635 0 : if ( ! active( ) ) return;
1636 :
1637 0 : if ( gui_state->input_received ) {
1638 : // GUI input received while this thread was preoccupied...
1639 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1640 0 : gui_state->input_received = false;
1641 0 : return;
1642 0 : } else {
1643 0 : std::lock_guard<std::mutex> lock(gui_state->set_values);
1644 0 : gui_state->userChoice_p = "Continue";
1645 0 : gui_state->output = std::promise<bool>( );
1646 0 : gui_state->input_needed = true;
1647 0 : }
1648 :
1649 0 : auto fut = gui_state->output.get_future();
1650 0 : fut.get( );
1651 0 : }
1652 :
1653 :
1654 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1655 : ////// Plot functions
1656 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1657 :
1658 0 : void FlagAgentDisplay::DisplayRaster(Int xdim, Int ydim, Vector<Float> &data, int frame)
1659 : {
1660 0 : if(data.nelements() != (uInt) xdim*ydim)
1661 : {
1662 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1663 0 : *logger_p << LogIO::WARN << "Error in data XY dimensions. Not plotting" << LogIO::POST;
1664 0 : return;
1665 : }
1666 : // cout << "panel id : " << frame << endl;
1667 :
1668 : // dataplotter_p->release( panel_p.getInt( ) );
1669 0 : erase( dataplotter_p, frame );
1670 :
1671 : // dataplotter_p->line(x, y, "blue", "time", panel_p.getInt() );
1672 0 : raster( dataplotter_p, frame, std::vector<float>(data.begin(),data.end()), xdim, ydim );
1673 : }
1674 :
1675 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1676 0 : void FlagAgentDisplay::DisplayLine(Int /*xdim*/, Vector<Double> &xdata, Vector<Float> &ydata, String label, String color, Bool hold, int frame)
1677 : {
1678 0 : if(xdata.nelements() != ydata.nelements())
1679 : {
1680 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1681 0 : *logger_p << LogIO::WARN << "X and Y plot data have different sizes. Not plotting " << LogIO::POST;
1682 0 : return;
1683 : }
1684 0 : if( hold==false ) erase( dataplotter_p, frame );
1685 0 : line( dataplotter_p, frame, std::vector<float>(xdata.begin(),xdata.end()), std::vector<float>(ydata.begin(),ydata.end()), color, label );
1686 : }
1687 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1688 :
1689 0 : void FlagAgentDisplay::DisplayScatter(Int /*xdim*/, Vector<Double> &xdata, Vector<Float> &ydata, String label, String color, Bool hold, int frame)
1690 : {
1691 0 : if(xdata.nelements() != ydata.nelements())
1692 : {
1693 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1694 0 : *logger_p << LogIO::WARN << "X and Y plot data have different sizes. Not plotting " << LogIO::POST;
1695 0 : return;
1696 : }
1697 0 : if( hold==false ) erase( dataplotter_p, frame );
1698 0 : scatter( dataplotter_p, frame, std::vector<float>(xdata.begin(),xdata.end()),
1699 0 : std::vector<float>(ydata.begin(),ydata.end()), color, label, "dot", 1, 4 );
1700 : }
1701 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1702 :
1703 : // Display scatter dots, with optional vertical error-bars, or circles or text labels, or all together.
1704 : // Send in vectors of size 0 for radii and pointlabels and error to disable them.
1705 0 : void FlagAgentDisplay::DisplayLineScatterError(std::shared_ptr<FlagAgentDisplay::plotter_t> plotter, String &plottype, Vector<Float> &xdata, Vector<Float> &ydata, String &errortype, Vector<Float> &error, String label, String color, int frame)
1706 : {
1707 : // Check X and Y shapes
1708 0 : if(xdata.nelements() != ydata.nelements())
1709 : {
1710 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1711 0 : *logger_p << LogIO::WARN << "X, Y plot data have different sizes. Not plotting." << LogIO::POST;
1712 0 : return;
1713 : }
1714 :
1715 0 : if(plottype==String("scatter"))
1716 : {
1717 : // Scatter-plot of X and Y
1718 0 : scatter( plotter, frame, std::vector<float>(xdata.begin(),xdata.end()),
1719 0 : std::vector<float>(ydata.begin(),ydata.end()),color,label,"dot",1,4 );
1720 : }
1721 0 : else if (plottype==String("line"))
1722 : {
1723 : // Line plot of X and Y
1724 0 : line( plotter, frame, std::vector<float>(xdata.begin(),xdata.end()),
1725 0 : std::vector<float>(ydata.begin(),ydata.end()),color,label );
1726 : }
1727 : else
1728 : {
1729 0 : return;
1730 : }
1731 :
1732 : // Check Error shape ( if not zero, must match xdata,ydata)
1733 0 : if(error.nelements()>0)
1734 : {
1735 0 : if(error.nelements()!=xdata.nelements())
1736 : {
1737 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1738 0 : *logger_p << LogIO::WARN << "Number of Error elements is different from data. Not plotting." << LogIO::POST;
1739 0 : return;
1740 : }
1741 :
1742 0 : if(errortype == "bar")
1743 : {
1744 0 : Vector<Double>pointerror(2);
1745 0 : Vector<Double>xval(2);
1746 0 : for ( Int onepoint=0; onepoint<(Int) error.nelements(); onepoint++)
1747 : {
1748 0 : xval[0]=xdata[onepoint];
1749 0 : xval[1]=xdata[onepoint];
1750 0 : pointerror[0]=ydata[onepoint] + error[onepoint];
1751 0 : pointerror[1]=ydata[onepoint] - error[onepoint];
1752 0 : line( plotter, frame, std::vector<float>(xval.begin(),xval.end()),
1753 0 : std::vector<float>(pointerror.begin(),pointerror.end()), color,"" );
1754 : }
1755 0 : }
1756 0 : else if(errortype == "separator")
1757 : {
1758 0 : Vector<Double>pointerror(2);
1759 0 : Vector<Double>xval(2);
1760 0 : for ( Int onepoint=0; onepoint<(Int) error.nelements(); onepoint++)
1761 : {
1762 0 : xval[0]=xdata[onepoint];
1763 0 : xval[1]=xdata[onepoint];
1764 0 : pointerror[0]=ydata[onepoint] + error[onepoint];
1765 0 : pointerror[1]=0;
1766 0 : line( plotter, frame, std::vector<float>(xval.begin(),xval.end()),
1767 0 : std::vector<float>(pointerror.begin(),pointerror.end()),"black","" );
1768 : }
1769 0 : }
1770 0 : else if(errortype == "circle")
1771 : {
1772 : // Check Circle shape ( if not zero, must match xdata,ydata)
1773 0 : Vector<Double>xval(1),yval(1);
1774 0 : for ( Int onepoint=0; onepoint<(Int) error.nelements(); onepoint++)
1775 : {
1776 0 : xval[0]=xdata[onepoint];
1777 0 : yval[0]=ydata[onepoint];
1778 : // function signature should allow a float for the error bar
1779 0 : scatter( plotter, frame, std::vector<float>(xval.begin(),xval.end()),
1780 0 : std::vector<float>(yval.begin(),yval.end()), color, "", "ellipse",
1781 0 : static_cast<Int>(error[onepoint]), 4 );
1782 : // Note : I think this plots the centre point too. If so, it's a repeat....
1783 : }
1784 0 : }
1785 : else
1786 : {
1787 0 : logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
1788 0 : *logger_p << LogIO::WARN << "Unknown error-plot type. Not plotting." << LogIO::POST;
1789 : }
1790 : }// if error
1791 :
1792 : // Do a similar thing for labels.
1793 : // NOTE : Cannot plot point-labels or text strings yet.
1794 :
1795 : }
1796 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1797 :
1798 :
1799 :
1800 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1801 : ////////////////////// GUI Layout Functions
1802 : //////////////////////////////////////////////////////////////////////////////////////////////////////
1803 :
1804 :
1805 0 : Bool FlagAgentDisplay :: setDataLayout()
1806 : {
1807 :
1808 0 : dock_xml_p = "\
1809 : <?xml version=\"1.0\" encoding=\"UTF-8\"?>\
1810 : <ui version=\"4.0\">\
1811 : <class>dock01</class>\
1812 : <widget class=\"QDockWidget\" name=\"dock01\">\
1813 : <property name=\"geometry\">\
1814 : <rect>\
1815 : <x>0</x>\
1816 : <y>0</y>\
1817 : <width>770</width>\
1818 : <height>120</height>\
1819 : </rect>\
1820 : </property>\
1821 : <property name=\"sizePolicy\">\
1822 : <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\
1823 : <horstretch>0</horstretch>\
1824 : <verstretch>0</verstretch>\
1825 : </sizepolicy>\
1826 : </property>\
1827 : <property name=\"minimumSize\">\
1828 : <size>\
1829 : <width>770</width>\
1830 : <height>87</height>\
1831 : </size>\
1832 : </property>\
1833 : <property name=\"windowTitle\">\
1834 : <string/>\
1835 : </property>\
1836 : <widget class=\"QWidget\" name=\"dockWidgetContents\">\
1837 : <layout class=\"QGridLayout\" name=\"gridLayout_2\">\
1838 : <item row=\"0\" column=\"0\">\
1839 : <layout class=\"QGridLayout\" name=\"gridLayout\">\
1840 : <item row=\"0\" column=\"0\">\
1841 : <widget class=\"QPushButton\" name=\"PrevBaseline\">\
1842 : <property name=\"text\">\
1843 : <string>Prev Baseline</string>\
1844 : </property>\
1845 : </widget>\
1846 : </item>\
1847 : <item row=\"0\" column=\"1\">\
1848 : <widget class=\"QPushButton\" name=\"NextBaseline\">\
1849 : <property name=\"text\">\
1850 : <string>Next Baseline</string>\
1851 : </property>\
1852 : </widget>\
1853 : </item>\
1854 : <item row=\"0\" column=\"2\">\
1855 : <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\
1856 : <property name=\"spacing\">\
1857 : <number>0</number>\
1858 : </property>\
1859 : <property name=\"sizeConstraint\">\
1860 : <enum>QLayout::SetMinimumSize</enum>\
1861 : </property>\
1862 : <item>\
1863 : <widget class=\"QCheckBox\" name=\"FixAntenna1\">\
1864 : <property name=\"text\">\
1865 : <string>Fix Antenna1</string>\
1866 : </property>\
1867 : </widget>\
1868 : </item>\
1869 : <item>\
1870 : <widget class=\"QCheckBox\" name=\"FixAntenna2\">\
1871 : <property name=\"text\">\
1872 : <string>Fix Antenna2</string>\
1873 : </property>\
1874 : </widget>\
1875 : </item>\
1876 : </layout>\
1877 : </item>\
1878 : <item row=\"0\" column=\"3\">\
1879 : <widget class=\"QPushButton\" name=\"NextSpw\">\
1880 : <property name=\"text\">\
1881 : <string>Next SPW</string>\
1882 : </property>\
1883 : </widget>\
1884 : </item>\
1885 : <item row=\"0\" column=\"4\">\
1886 : <widget class=\"QPushButton\" name=\"NextScan\">\
1887 : <property name=\"text\">\
1888 : <string>Next Scan</string>\
1889 : </property>\
1890 : </widget>\
1891 : </item>\
1892 : <item row=\"0\" column=\"5\">\
1893 : <widget class=\"QPushButton\" name=\"NextField\">\
1894 : <property name=\"text\">\
1895 : <string>Next Field</string>\
1896 : </property>\
1897 : </widget>\
1898 : </item>\
1899 : <item row=\"0\" column=\"6\">\
1900 : <widget class=\"QPushButton\" name=\"StopDisplay\">\
1901 : <property name=\"text\">\
1902 : <string>Stop Display</string>\
1903 : </property>\
1904 : </widget>\
1905 : </item>\
1906 : <item row=\"0\" column=\"7\">\
1907 : <widget class=\"QPushButton\" name=\"Quit\">\
1908 : <property name=\"text\">\
1909 : <string>Quit</string>\
1910 : </property>\
1911 : </widget>\
1912 : </item>\
1913 : </layout>\
1914 : </item>\
1915 : </layout>\
1916 : </widget>\
1917 : </widget>\
1918 : <resources/>\
1919 : <connections/>\
1920 : </ui>\
1921 : ";
1922 :
1923 0 : return true;
1924 :
1925 : }// end of SetLayout
1926 :
1927 :
1928 0 : Bool FlagAgentDisplay :: setReportLayout()
1929 : {
1930 :
1931 0 : report_dock_xml_p = "\
1932 : <?xml version=\"1.0\" encoding=\"UTF-8\"?>\
1933 : <ui version=\"4.0\">\
1934 : <class>dock01</class>\
1935 : <widget class=\"QDockWidget\" name=\"dock01\">\
1936 : <property name=\"geometry\">\
1937 : <rect>\
1938 : <x>0</x>\
1939 : <y>0</y>\
1940 : <width>320</width>\
1941 : <height>80</height>\
1942 : </rect>\
1943 : </property>\
1944 : <property name=\"sizePolicy\">\
1945 : <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\
1946 : <horstretch>0</horstretch>\
1947 : <verstretch>0</verstretch>\
1948 : </sizepolicy>\
1949 : </property>\
1950 : <property name=\"minimumSize\">\
1951 : <size>\
1952 : <width>320</width>\
1953 : <height>80</height>\
1954 : </size>\
1955 : </property>\
1956 : <property name=\"windowTitle\">\
1957 : <string/>\
1958 : </property>\
1959 : <widget class=\"QWidget\" name=\"dockWidgetContents\">\
1960 : <property name=\"enabled\">\
1961 : <bool>true</bool>\
1962 : </property>\
1963 : <property name=\"sizePolicy\">\
1964 : <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\
1965 : <horstretch>0</horstretch>\
1966 : <verstretch>0</verstretch>\
1967 : </sizepolicy>\
1968 : </property>\
1969 : <layout class=\"QGridLayout\" name=\"gridLayout\">\
1970 : <item row=\"0\" column=\"0\">\
1971 : <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\
1972 : <item>\
1973 : <widget class=\"QPushButton\" name=\"Prev\">\
1974 : <property name=\"text\">\
1975 : <string>Prev</string>\
1976 : </property>\
1977 : </widget>\
1978 : </item>\
1979 : <item>\
1980 : <widget class=\"QPushButton\" name=\"Next\">\
1981 : <property name=\"text\">\
1982 : <string>Next</string>\
1983 : </property>\
1984 : </widget>\
1985 : </item>\
1986 : <item>\
1987 : <widget class=\"QPushButton\" name=\"Quit\">\
1988 : <property name=\"text\">\
1989 : <string>Quit</string>\
1990 : </property>\
1991 : </widget>\
1992 : </item>\
1993 : </layout>\
1994 : </item>\
1995 : </layout>\
1996 : </widget>\
1997 : </widget>\
1998 : <resources/>\
1999 : <connections/>\
2000 : </ui>\
2001 : ";
2002 :
2003 0 : return true;
2004 :
2005 : }
2006 :
2007 : #endif // USE_GRPC
2008 :
2009 : } //# NAMESPACE CASA - END
2010 :
2011 :
|