void adamtest ( int * status ) { if (*status != SAI__OK) return; msgOut("MSG1", "This text should not appear for msgOut", status ); msgSeti("TEST", 5); msgOut(" ", " Testing ^^ %% % $ $$ %ET - $TESTOBJ ^TEST",status); msgOut( " ", " Testing $ %ET Again %%ET ^^$", status ); msgOut(" ", "$$DOLLAR ^^CARET %%PERCENT at start of string", status); /* Make up a bad status */ *status = MSG__SYNER; errRep( " ", "This is the error message ^STATUS embedded", status ); errRep( "MSG1", "This text should not appear", status ); errRep( " ", "Should be expanded: %ET as 'EXPOSURE_TIME'", status); errRep( " ", "Object $TESTOBJ %s %XX should be somewhere", status ); errRep( " ", "Multiple %ET and ^STATUS and %TESTOBJ and %BLAH", status ); errRep( " ", "Double up %% escape $$ characters", status ); msgSetc( "X1", STRING ); msgSetc( "X2", STRING); msgSetc( "X3", STRING); msgSetc( "X4", STRING); msgSetc( "X5", STRING); msgSetc( "X6", STRING); errRep( " ","Overflow: ^X1:^X2:^X3:^X4:^X5:^X6", status ); }
void handleVoteMsg(char* username , char* msgIn) { WDL_String msgOut(username) ; msgOut.Append(" votes to set ") ; char bpibpm[4] = "\0" ; strncpy(bpibpm , msgIn += VOTE_CHAT_MESSAGE_LEN , 3) ; msgOut.Append(bpibpm) ; msgOut.Append(" to ") ; strncpy(bpibpm , msgIn += 4 , 3) ; msgOut.Append(bpibpm) ; chat_addline(USERNAME_TEAMSTREAM , msgOut.Get()) ; }
/* * main loop for the CarbonGui object */ void CARBON_GUI::run() { int i; int o = 0; //UInt32 finalTicks; while(!quit) { lock(); /* lock before iterating on channel array ... if all is sane * nobody can modify the channel list while we are managing it */ wait(); /* wait the tick signal from jmixer */ /* now iterate an channels updating lcd and pos as necessary */ for(i=0;i<MAX_CHANNELS;i++) { if(channel[i]) { if(new_pos[i]) { int newPos = (int)(ch_pos[i]*1000); channel[i]->setPos(newPos); new_pos[i] = false; } if(new_lcd[i]) { channel[i]->setLCD(ch_lcd[i]); new_lcd[i] = false; } channel[i]->run(); /* propagate tick on each channel */ //QDFlushPortBuffer(GetWindowPort(channel[i]->window),NULL); } } if(playlistManager->isTouched()) playlistManager->untouch(); /* reset playlistManager update flag */ unlock(); if(meterShown()) updateVumeters(); if(statusText && msgList->len() > 0) { /* statusLock(); if(statusText && !quit) { err=TXNSetTypeAttributes(statusText,3,attributes,kTXNUseCurrentSelection,kTXNUseCurrentSelection); if(err!=noErr) msg->warning("Can't set status text attributes (%d)!!",err); } statusUnlock(); */ while(msgList->len() > 0) { Entry *msg = msgList->begin(); char *txt = (char *)msg->get_value(); if(txt) { msgOut(txt); free(txt); } delete msg; } } // Delay(2,&finalTicks); /* XXX - DISABLED BEACAUSE NOW TICK IS SIGNALED BY JMIXER */ if(IsWindowVisible(bufferInspector->window)) bufferInspector->run(); } }
void smurf_rawrewrtsc2wcs( int * status ) { size_t i; Grp *igrp = NULL; /* Input group */ size_t size; /* Number of files in input group */ if (*status != SAI__OK) return; ndfBegin(); /* Read the input file group */ kpg1Rgndf( "NDF", 0, 1, "", &igrp, &size, status ); for (i=1; i<=size && ( *status == SAI__OK ); i++) { int indf = NDF__NOID; smfData *data = NULL; AstFrameSet * fixedwcs = NULL; int isok = 1; /* First open in READ mode as a sanity check */ smf_open_file( igrp, i, "READ", 0, &data, status ); if (*status != SAI__OK) break; if (data->hdr->instrument != INST__SCUBA2) { isok = 0; msgOut( "", "This command only works on SCUBA-2 data files", status ); } /* Get a fixed WCS frameset */ if (isok) { smf_create_tswcs( data->hdr, &fixedwcs, status ); } /* close up and skip if this is not a good file */ smf_close_file( &data, status ); if (!isok) continue; /* Now we try to update the file using NDF */ ndgNdfas( igrp, i, "UPDATE", &indf, status ); ndfPtwcs( fixedwcs, indf, status ); ndfAnnul( &indf, status ); } /* Cleanup */ grpDelet( &igrp, status); ndfEnd( status ); }
void InchieKey::perform (void){ keyState = (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)) ? 0 : 1; if (keyState != keyStateLast){ keyStateLast = keyState; sprintf(address, "/%s/%d", type, index); OSCMessage msgOut(address); msgOut.add(keyState); msgOut.send(oscBuf); slipSerial.sendPacket(oscBuf.buffer, oscBuf.length); if (keyState) LEDON; else LEDOFF; } }
HRESULT CUIClientConnector::ProcessIncomingMsg( CMBCSocket* pMBCSock, int nMsgType, char* bufferIn, int nUsed ) { if (nMsgType == embmsgtype_UIServerToUIClientMsg) { HRESULT hr = S_OK; ST_EMBTRANSMSG msgIn(nMsgType); UnPackMBCMsg(bufferIn, nUsed, msgIn); ST_EMBTRANSMSG msgOut(embmsgtype_UIClientToUIServerMsg); if (m_pIProcess) { hr = m_pIProcess->OnMessage(m_nMaster, msgIn.strData, msgOut.strData); } if (!msgOut.strData.IsEmpty()) { CEMBAutoBuffer szbuff(msgOut); int nRetUsed = 0; PackMBCMsg(msgOut, szbuff, szbuff.GetSize(), nRetUsed); //send back to dispatch hr = send(*pMBCSock, szbuff, nRetUsed, 0); if(hr == SOCKET_ERROR) { hr = WSAGetLastError(); CFWriteLog(0, TEXT("send back to uisvr error = %d!"), hr); ASSERT(FALSE); } } return hr; } else { return __super::ProcessIncomingMsg(pMBCSock, nMsgType, bufferIn, nUsed); } }
void smurf_mon( int * status ) { /* Local variables */ char taskname[PAR__SZNAM+1]; char appname[NDF__SZAPP+1]; char filter[PAR__SZNAM+PAR__SZNAM+1]; int ngrp0; /* Number of grp ids at start */ int ngrp1; /* Number of grp ids at end */ int nloc0; /* Number of active HDS Locators at start */ int nloc1; /* Number of active HDS Locators at end */ int memory_caching; /* Is AST current caching unused memory? */ int emslev1; /* EMS level on entry */ int emslev2; /* EMS level on exit */ if ( *status != SAI__OK ) return; /* Read the input error message stack level */ emsLevel( &emslev1 ); /* Initialise AST */ astBegin; memory_caching = astTune( "MemoryCaching", 1 ); /* Register our status variable with AST */ astWatch( status ); /* If we are watching a particular memory Id reported by astActiveMemory we set the watch point here. */ /* astWatchMemory( 29 ); */ /* For debugging, watch one of the leaked GRP identifiers listed by the call to grpWatch at the end of this routine (if any). */ /* grpWatch( 3129345, status ); */ /* Mark any currently active NDF parameters, so that they will not be cancelled by the call to ndfCancl at the end of this function. */ ndfCancl( "*", status ); /* Find out the task name and provenance name we were invoked with */ smf_get_taskname( taskname, NULL, status ); /* Get the GRP and HDS status for leak checking - need the task name to mask out parameter names. Also need to mask out the monlith name */ one_strlcpy( filter, "!SMURF_MON,!", sizeof(filter), status); one_strlcat( filter, taskname, sizeof(filter), status ); grpInfoi( NULL, 0, "NGRP", &ngrp0, status ); hdsInfoI( NULL, "LOCATORS", filter, &nloc0, status ); /* Update the application name in the NDF history recording to include the version number of the application */ snprintf( appname, NDF__SZAPP, "%-*s (%s V%s)", PAR__SZNAM, taskname, PACKAGE_UPCASE, PACKAGE_VERSION); ndfHappn( appname, status ); /* Begin a GRP NDF history block. This causes the contents of GRP groups to be appended to default history text added to any NDFs during the block. */ ndgBeggh( status ); /* Call the subroutine associated with the requested task */ if (strcmp( taskname, "BADBOLOS" ) == 0 ) { smurf_extinction( status ); } else if (strcmp( taskname, "CALCDARK" ) == 0 ) { smurf_calcdark( status ); } else if (strcmp( taskname, "CALCFLAT" ) == 0 ) { smurf_calcflat( status ); } else if (strcmp( taskname, "CALCNOISE" ) == 0 ) { smurf_calcnoise( status ); } else if (strcmp( taskname, "CALCQU" ) == 0 ) { smurf_calcqu( status ); } else if (strcmp( taskname, "CALCRESP" ) == 0 ) { smurf_calcresp( status ); } else if (strcmp( taskname, "COPYFLAT" ) == 0 ) { smurf_copyflat( status ); } else if (strcmp( taskname, "DREAMSOLVE" ) == 0 ) { smurf_dreamsolve( status ); } else if (strcmp( taskname, "DREAMWEIGHTS" ) == 0 ) { smurf_dreamweights( status ); } else if (strcmp( taskname, "DSUTILS" ) == 0 ) { smurf_dsutils( status ); } else if (strcmp( taskname, "EXTINCTION" ) == 0 ) { smurf_extinction( status ); } else if (strcmp( taskname, "FIT1D" ) == 0 ) { smurf_fit1d( status ); } else if (strcmp( taskname, "FIXSTEPS" ) == 0 ) { smurf_fixsteps( status ); } else if (strcmp( taskname, "FLATFIELD" ) == 0 ) { smurf_flatfield( status ); } else if (strcmp( taskname, "FTS2DEGLITCH" ) == 0 ) { smurf_fts2_deglitch( status ); } else if (strcmp( taskname, "FTS2FLATFIELD" ) == 0 ) { smurf_fts2_flatfield( status ); } else if (strcmp( taskname, "FTS2FREQCORR" ) == 0 ) { smurf_fts2_freqcorr( status ); } else if (strcmp( taskname, "FTS2SPLIT" ) == 0 ) { smurf_fts2_split( status ); } else if (strcmp( taskname, "FTS2INIT" ) == 0 ) { smurf_fts2_init( status ); } else if (strcmp( taskname, "FTS2MASKMAP" ) == 0 ) { smurf_fts2_maskmap( status ); } else if (strcmp( taskname, "FTS2OPCORR" ) == 0 ) { smurf_fts2_spatialwcs( status ); } else if (strcmp( taskname, "FTS2PHASECORR" ) == 0 ) { smurf_fts2_phasecorr( status ); } else if (strcmp( taskname, "FTS2PHASECORRDS" ) == 0 ) { smurf_fts2_phasecorrds( status ); } else if (strcmp( taskname, "FTS2PORTIMBAL" ) == 0 ) { smurf_fts2_portimbal( status ); } else if (strcmp( taskname, "FTS2REMOVEBSE" ) == 0 ) { smurf_fts2_removebse( status ); } else if (strcmp( taskname, "FTS2SPECTRUM" ) == 0 ) { smurf_fts2_spectrum( status ); } else if (strcmp( taskname, "FTS2TRANSCORR" ) == 0 ) { smurf_fts2_transcorr( status ); } else if (strcmp( taskname, "GSD2ACSIS" ) == 0 ) { smurf_gsd2acsis( status ); } else if (strcmp( taskname, "GSDSHOW" ) == 0 ) { smurf_gsdshow( status ); } else if (strcmp( taskname, "IMPAZTEC" ) == 0 ) { smurf_impaztec( status ); } else if (strcmp( taskname, "MAKECUBE" ) == 0 ) { smurf_makecube( status ); } else if (strcmp( taskname, "MAKEMAP" ) == 0 ) { smurf_makemap( status ); } else if (strcmp( taskname, "RAWFIXMETA" ) == 0 ) { smurf_rawfixmeta( status ); } else if (strcmp( taskname, "RAWPRESS" ) == 0 ) { smurf_rawpress( status ); } else if (strcmp( taskname, "RAWRECREATEWCS" ) == 0 ) { smurf_rawrecreatewcs( status ); } else if (strcmp( taskname, "RAWREWRTSC2WCS" ) == 0 ) { smurf_rawrewrtsc2wcs( status ); } else if (strcmp( taskname, "RAWUNPRESS" ) == 0 ) { smurf_rawunpress( status ); } else if (strcmp( taskname, "REMSKY" ) == 0 ) { smurf_remsky( status ); } else if (strcmp( taskname, "SC2CLEAN" ) == 0 ) { smurf_sc2clean( status ); } else if (strcmp( taskname, "SC2CONCAT" ) == 0 ) { smurf_sc2concat( status ); } else if (strcmp( taskname, "SC2EXPANDMODEL" ) == 0 ) { smurf_sc2expandmodel( status ); } else if (strcmp( taskname, "SC2FFT" ) == 0 ) { smurf_sc2fft( status ); } else if (strcmp( taskname, "SC2FILTERMAP" ) == 0 ) { smurf_sc2filtermap( status ); } else if (strcmp( taskname, "SC2MAPFFT" ) == 0 ) { smurf_sc2mapfft( status ); } else if (strcmp( taskname, "SC2PCA" ) == 0 ) { smurf_sc2pca( status ); } else if (strcmp( taskname, "SC2SIM" ) == 0 ) { smurf_sc2sim( status ); } else if (strcmp( taskname, "SC2THREADTEST" ) == 0 ) { smurf_sc2threadtest( status ); } else if (strcmp( taskname, "SKYNOISE" ) == 0 ) { smurf_skynoise( status ); } else if (strcmp( taskname, "SMURFCOPY" ) == 0 ) { smurf_smurfcopy( status ); } else if (strcmp( taskname, "SMURFHELP" ) == 0 ) { smurf_smurfhelp( status ); } else if (strcmp( taskname, "STACKFRAMES" ) == 0 ) { smurf_stackframes( status ); } else if (strcmp( taskname, "STARECALC" ) == 0 ) { smurf_starecalc( status ); } else if (strcmp( taskname, "TILEINFO" ) == 0 ) { smurf_tileinfo( status ); } else if (strcmp( taskname, "TILELIST" ) == 0 ) { smurf_tilelist( status ); } else if (strcmp( taskname, "TIMESORT" ) == 0 ) { smurf_timesort( status ); } else if (strcmp( taskname, "UNMAKECUBE" ) == 0 ) { smurf_unmakecube( status ); } else if (strcmp( taskname, "UNMAKEMAP" ) == 0 ) { smurf_unmakemap( status ); } else { *status = SAI__ERROR; msgSetc( "TASK", taskname ); errRep( "smurf_mon", "Unrecognized taskname: ^TASK", status); } /* End the GRP NDF history block. */ ndgEndgh( status ); /* Clear cached info from sc2ast_createwcs. */ sc2ast_createwcs(SC2AST__NULLSUB, NULL, NULL, NULL, NO_FTS, NULL, status); /* Clear WVM caches (one for each thread). */ smf_calc_wvm_clear( status ); /* Free AST resources */ astTune( "MemoryCaching", memory_caching ); astEnd; /* Check for GRP leaks Do this in a new error reporting context so * that we get the correct value even if an error has occurred. */ errBegin( status ); grpInfoi( NULL, 0, "NGRP", &ngrp1, status ); /* If there are more active groups now than there were on entry, * there must be a problem (GRP identifiers are not being freed * somewhere). So report it. */ if (*status == SAI__OK && ngrp1 > ngrp0) { msgBlank( status ); msgSetc( "NAME", taskname ); msgSeti( "NGRP0", ngrp0 ); msgSeti( "NGRP1", ngrp1 ); msgOut( " ", "WARNING: The number of active " "GRP identifiers increased from ^NGRP0 to ^NGRP1 " "during execution of ^NAME (" PACKAGE_UPCASE " programming " " error).", status); msgBlank(status); grpWatch( 0, status ); } errEnd( status ); /* The NDF library registers locators with SUBPAR for any NDFs that are opened directly using ndfAssoc or ndfExist. These locators are only annulled when the associated parameters are cancelled, but most smurf applications do not explicitly cancel their NDF parameters. This means that such locators are picked up by the following check for dangling HDS locators. In order to prevent this, we cancel any remaining NDF parameters now, excluding any that were marked by the call to ndfCancl at the start of this routine. */ ndfCancl( " ", status ); /* Check for HDS leaks Do this in a new error reporting context so * that we get the correct value even if an error has occurred. */ errBegin( status ); hdsInfoI( NULL, "LOCATORS", filter, &nloc1, status ); /* If there are more active locators now than there were on entry, * there must be a problem (HDS locators are not being freed * somewhere). So report it. */ if (*status == SAI__OK && nloc1 > nloc0) { msgBlank( status ); msgSetc( "NAME", taskname ); msgSeti( "NLOC0", nloc0 ); msgSeti( "NLOC1", nloc1 ); msgOut( " ", "WARNING: The number of active " "HDS Locators increased from ^NLOC0 to ^NLOC1 " "during execution of ^NAME (" PACKAGE_UPCASE " programming " " error).", status); msgBlank(status); hdsShow("LOCATORS", status); hdsShow("FILES", status); printf("filter - %s\n",filter); } errEnd( status ); /* Read the exitt error message stack level */ emsLevel( &emslev2 ); if (*status == SAI__OK && emslev1 != emslev2 ) { errMark(); msgBlank( status ); msgSetc( "NAME", taskname ); msgSeti( "LV1", emslev1); msgSeti( "LV2", emslev2); msgOut( " ", "WARNING: EMS Stack level went from ^LV1 to ^LV2" " during execution of ^NAME (" PACKAGE_UPCASE " programming" " error).", status ); msgBlank(status); errRlse(); } /* configure AST --with-memdebug, and uncomment the following lines to see how much memory usage SMURF hit at its peak */ /* { size_t memcurrent,mempeak; astMemoryStats( 0, &mempeak, &memcurrent ); msgOutf( "", "SMURF: === current /peak memory usage: %zu / %zu MiB ===", status, memcurrent/SMF__MIB, mempeak/SMF__MIB ); } */ /* The astCheckMemory function does nothing unless AST has been compiled * with the MEM_DEBUG flag. If this is the case, then it reports the number * of memory blocks that have not been freed (useful for identifying memory * leaks). Use astActiveMemory() below to list all active memory and * then use astWatchMemory() at the start of this routine to get reports * when a particular ID is used. Set a breakpoint in the debugger for * astMemoryAlarm_ */ astActiveMemory("Exit:"); astCheckMemory; }
static int smf1_check_steps( const char *param, int first, dim_t nx, double sizetol, int nold, int nnew, smfStepFix *oldsteps, smfStepFix *newsteps, int *status ){ /* * Name: * smf1_check_steps * Purpose: * Compare two sets of steps, issuing a warning for each step that * has changed significantly. * Invocation: * int smf1_check_steps( const char *param, int first, dim_t nx, * double sizetol, int nold, int nnew, * smfStepFix *oldsteps, smfStepFix *newsteps, * int *status ) * Arguments: * param = const char * (Given) * Name of parameter to use when asking the user whether to * continue to look for further changes. * first = int (Given) * The index of the first change to report. * nx = dim_t (Given) * The length of the first axis of the bolometer array. * sizetol = double (Given) * The minimum significant relative error in step size. * nold = int (Given) * The number of steps in the "oldsteps" array. * nnew = int (Given) * The number of steps in the "newsteps" array. * oldsteps = smfStepFix * (Given and Returned) * A pointer to the first element of an array of smfStepFix structures * describing the steps fixed in a previous invocation of this program. * The array is sorted on exit. * newsteps = smfStepFix * (Given and Returned) * A pointer to the first element of an array of smfStepFix structures * describing the steps fixed in the current invocation of this program. * The array is sorted on exit. * status = int * (Given and Returned) * Pointer to global status. * Description: * Firstly, an attempt it made to associated each old step with a * corresponding new step (i.e. a new step that occurs at the same * time and in the same bolometer as the old step). Warning messages * are issued about each old step for which no corresponding new step * can be found, or for which the corresponding new step has a * significantly different height to the old step. Finally, warnings * messages are also issued for each new step that has not been * associated with an old step. * Returned Value: * Zero if no significant differences were found. Non-zero otherwise. */ /* Local Variables: */ double abslim; double dsize; double dsize_min; int *fnew; int *new_flags; int cont; int inew; int iold; int jnew; int match; int result; smfStepFix *pnew; smfStepFix *pold; /* Initialise the returned value. */ result = 0; /* Check the inherited status. */ if( *status != SAI__OK ) return result; /* Find the absolute minimum significant difference between step sizes. This is "sizetol" times the clipped RMS step size in the new steps. */ abslim = sizetol*smf1_get_rmssize( nnew, newsteps, status ); msgSetd( "T", abslim ); msgOut( "", "Ignoring differences in step size smaller than ^T", status ); msgBlank( status ); /* Allocate memory to hold an array with one element for each new step. Each element holds zero if the new step has not yet been associated with any old step. Otherwise, it holds the one-based index of the associated old step. Initialise it to hold zero at every element. */ new_flags = astCalloc( nnew, sizeof( *new_flags ) ); if( *status == SAI__OK ) { /* Loop round each old step. */ pold = oldsteps; for( iold = 0; iold < nold; iold++,pold++ ) { /* Ignore old steps with bolometer indicies greater than 5000 */ if( pold->ibolo > 5000 ) continue; /* Indicate no new step has yet been associated with the old step. */ jnew = -1; dsize_min = VAL__MAXD; match = 0; /* Loop round all new steps. */ pnew = newsteps; fnew = new_flags; for( inew = 0; inew < nnew; inew++,pnew++,fnew++ ) { /* Ignore this new step if it has already been associated with a previous old step. */ if( ! *fnew ) { /* See if the current new and old steps occur in the same bolometer and have overlapping time spans. If so they are considered to be at the same time. */ if( pold->ibolo == pnew->ibolo && pold->start <= pnew->end && pold->end >= pnew->start ) { /* Get the difference in step size between the old and new steps. */ dsize = fabs( pold->size - pnew->size ); /* Note the index of the matching new step that is most similar in height to the old step. */ if( dsize < dsize_min ) { jnew = inew; dsize_min = dsize; } /* If the old and new step heights are about the same then we associate the new step with the old step. Store the (one based) index of the corresponding old step. We do not need to check any more new steps, so break out of the new step loop. */ if( dsize < abslim || dsize < sizetol*fabs( 0.5*( pold->size + pnew->size ) ) ) { match = 1; *fnew = iold + 1; break; } } } } /* If a new step was found at the same time and place as the old step, and with the same height, pass on to the next old step. */ if( ! match ) { /* If no new step was found at the same time and place as the old step, an old step has dissappeared. */ if( jnew == -1 ) { /* If the old step was of significant height, tell the user. */ if( fabs( pold->size ) > abslim ){ result++; if( result >= first ) { msgSeti( "N", result ); msgSeti( "I", pold->id ); msgSetc( "W", pold->corr ? "secondary" : "primary" ); msgOut( "", "^N: An old ^W step (index ^I) is no longer found:", status ); msgSeti( "B", pold->ibolo ); msgSeti( "X", pold->ibolo % nx ); msgSeti( "Y", pold->ibolo / nx ); msgOut( "", " Bolometer = ^B (^X,^Y)", status ); msgSeti( "S", pold->start ); msgSeti( "E", pold->end ); msgOut( "", " Time slice range = ^S:^E", status ); msgSetd( "H", pold->size ); msgOut( "", " Height = ^H", status ); parGet0l( param, &cont, status ); parCancl( param, status ); if( !cont || *status != SAI__OK ) break; msgBlank( status ); } } /* If one or more new step were found at the same time and place as the old step (but with a significantly different height), tell the user about the change in height. */ } else { pnew = newsteps + jnew; result++; if( result >= first ) { msgSeti( "I", result ); msgSetd( "O", pold->size ); msgSetd( "N", pnew->size ); msgOut( "", "^I: Step size changed from ^O to ^N:", status ); msgSeti( "I", pnew->id ); msgSetc( "W", pnew->corr ? "secondary" : "primary" ); msgOut( "", " New index = ^I (^W)", status ); msgSeti( "I", pold->id ); msgSetc( "W", pold->corr ? "secondary" : "primary" ); msgOut( "", " Old index = ^I (^W)", status ); msgSeti( "B", pold->ibolo ); msgSeti( "X", pold->ibolo % nx ); msgSeti( "Y", pold->ibolo / nx ); msgOut( "", " Bolometer = ^B (^X,^Y)", status ); msgSeti( "S", pold->start ); msgSeti( "E", pold->end ); msgOut( "", " Old time slice range = ^S:^E", status ); msgSeti( "S", pnew->start ); msgSeti( "E", pnew->end ); msgOut( "", " New time slice range = ^S:^E", status ); parGet0l( param, &cont, status ); parCancl( param, status ); if( !cont || *status != SAI__OK ) break; msgBlank( status ); } } } } /* We have now checked all old steps for matching new steps. If no significant change has yet been found, look for new steps that have not been associated with an old step. */ pnew = newsteps; fnew = new_flags; for( inew = 0; inew < nnew && cont; inew++,pnew++,fnew++ ) { if( ! *fnew ) { /* If the new step is off significant height, tell the user. */ if( fabs( pnew->size ) > abslim ){ result++; if( result >= first ) { msgSeti( "N", result ); msgSeti( "I", pnew->id ); msgSetc( "W", pnew->corr ? "secondary" : "primary" ); msgOut( "", "^N: A new ^W step (index ^I) was found:", status ); msgSeti( "B", pnew->ibolo ); msgSeti( "X", pnew->ibolo % nx ); msgSeti( "Y", pnew->ibolo / nx ); msgOut( "", " Bolometer = ^B (^X,^Y)", status ); msgSeti( "S", pnew->start ); msgSeti( "E", pnew->end ); msgOut( "", " Time slice range = ^S:^E", status ); msgSetd( "H", pnew->size ); msgOut( "", " Height = ^H", status ); parGet0l( param, &cont, status ); parCancl( param, status ); if( !cont || *status != SAI__OK ) break; msgBlank( status ); } } } } } /* Free resources. */ new_flags = astFree( new_flags ); /* Return the result. */ return result; }
static smfStepFix *smf1_read_steps( FILE *fd, double dcthresh0, dim_t dcsmooth0, dim_t dcfitbox0, int dcmaxsteps0, int dclimcorr0, size_t nrej0, int nstep0, int *nstep, int *status ) { /* * Name: * smf1_read_steps * Purpose: * Read step descriptions from a file, and check global values. * Invocation: * smfStepFix *smf1_read_steps( FILE *fd, double dcthresh0, * dim_t dcsmooth0, dim_t dcfitbox0, * int dcmaxsteps0, int dclimcorr0, * size_t nrej0, int nstep0, int *nstep, * int *status ) * Arguments: * fd = FILE * (Given) * A file descriptor from which to read the details of a set of * steps. * dcthresh0 = double (Given) * Expected value of DCTHRESH. * dcsmooth0 = dim_t (Given) * Expected value of DCSMOOTH. * dcfitbox0 = dim_t (Given) * Expected value of DCFITBOX. * dcmaxsteps0 = int (Given) * Expected value of DCMAXSTEPS. * dclimcorr = int (Given) * Expected value of DCLIMCORR. * nrej0 = size_t (Given) * The expected number of bolometers rejected. * nstep0 = int (Given) * The expected number of step fixes. * nstep = int * (Returned) * The number of steps fixes read from the file. * status = int* (Given and Returned) * Pointer to global status. * Description: * Reads information from the supplied file, returning an array of * step fixes. It also issues warnings if any of the global values * read from the file are not equal to the supplied expected values. * Returned Value: * A pointer to an array of smfStepFix structures describing the * steps fixes read form the file. The length of this array is equal * to "*nstep". The array should be freed using astFree when no longer * needed. */ /* Local Variables: */ smfStepFix *result; char buf[ 256 ]; char *c; double dval; double size; int bad; int corr; int end; int ibolo; int iline; int istep; int ival; int nc; int nold; int stage; int start; /* Initialise */ result = NULL; *nstep = 0; /* Check the inherited status. */ if( *status != SAI__OK ) return result; /* Indicate we have not yet reached the tabular data. */ stage = 0; /* Initialise the index of the next step */ istep = 0; /* Indicate we do not yet know how many steps are described in the text file. */ nold = -1; /* Indicate no bad lines found yet. */ bad = 0; /* Loop round reading lines of text from the supplied file until an illegal line is read or the end of file is reached. */ iline = 0; while( !bad && fgets( buf, sizeof(buf), fd ) && *status == SAI__OK ) { iline++; /* Remove trailing white space. */ c = buf + strlen( buf ) - 1; while( isspace( *c ) && c > buf ) c--; c[ 1 ] = 0; /* scanf indicates success if the strings do not fail to match before the end of the shorter of the two. So we need to check that sufficient characters are compared. Initialise the number of characters compared. */ nc = 0; /* If we are not yet in the tabular data, look for header lines, and issue a message if the old value is different to the new value. */ if( stage == 0 ) { if( sscanf( buf, "# Number of steps fixed = %d%n", &ival, &nc ) && nc > 26 ) { if( ival != nstep0 ) { msgSeti( "O", ival ); msgSeti( "N", nstep0 ); msgOut( "", "No. of steps fixed changed from ^O to ^N", status ); } nold = ival; } else if( sscanf( buf, "# Number of bolometers rejected = %d%n", &ival, &nc ) && nc > 34 ) { if( ival != (int) nrej0 ) { msgSeti( "O", ival ); msgSeti( "N", nrej0 ); msgOut( "", "No. of bolometers rejected changed from ^O to ^N", status ); } } else if( sscanf( buf, "# DCFITBOX = %d%n", &ival, &nc ) && nc > 13 ) { if( ival != (int) dcfitbox0 ) { msgSeti( "O", ival ); msgSeti( "N", dcfitbox0 ); msgOut( "", "Warning: DCFITBOX changed from ^O to ^N", status ); } } else if( sscanf( buf, "# DCMAXSTEPS = %d%n", &ival, &nc ) && nc > 14 ) { if( ival != dcmaxsteps0 ) { msgSeti( "O", ival ); msgSeti( "N", dcmaxsteps0 ); msgOut( "", "Warning: DCMAXSTEPS changed from ^O to ^N", status ); } } else if( sscanf( buf, "# DCLIMCORR = %d%n", &ival, &nc ) && nc > 14 ) { if( ival != dclimcorr0 ) { msgSeti( "O", ival ); msgSeti( "N", dclimcorr0 ); msgOut( "", "Warning: DCLIMCORR changed from ^O to ^N", status ); } } else if( sscanf( buf, "# DCSMOOTH = %d%n", &ival, &nc ) && nc > 18 ) { if( ival != (int) dcsmooth0 ) { msgSeti( "O", ival ); msgSeti( "N", dcsmooth0 ); msgOut( "", "Warning: DCSMOOTH changed from ^O to ^N", status ); } } else if( sscanf( buf, "# DCTHRESH = %lg%n", &dval, &nc ) && nc > 13 ) { if( fabs( dval - dcthresh0 ) > 1.0E-10 ) { msgSetd( "O", dval ); msgSetd( "N", dcthresh0 ); msgOut( "", "Warning: DCTHRESH changed from ^O to ^N", status ); } /* Look for the line that marks the start of the tabular data. */ } else if( !strcmp( buf, "# istep start end ibolo size corr" ) ) { stage = 1; msgBlank( status ); /* Allocate the returned array. */ result = astMalloc( nold*sizeof( *result ) ); *nstep = nold; /* Abort if an illegal header line is read. */ } else if( strcmp( buf, "#" ) && strncmp( buf, "# Steps fixed in '", 18 ) ) { bad = 1; } /* If we are now reading tabular data... */ } else { /* Extract the numerical values from the line of text. */ if( sscanf( buf, "%d %d %d %d %lg %d%n", &ival, &start, &end, &ibolo, &size, &corr, &nc ) == 6 && nc > 14 ) { /* Report an error if there is a jump in the step index (indicates lines missing from the supplied file). */ if( ival != istep ) { *status = SAI__ERROR; msgSeti( "I", istep ); errRep( "", "Step ^I data not found in old steps file:", status ); bad = 1; /* Otherwise, store the numerical values in the next element of the returned array. */ } else if( istep < nold ){ result[ istep ].id = ival; result[ istep ].ibolo = ibolo; result[ istep ].start = start; result[ istep ].end = end; result[ istep ].size = size; result[ istep ].corr = corr; } /* Increment the index of the next step to check. */ istep++; /* Abort if the numerical values cannot be read from the line of text. */ } else { bad = 1; } } } /* Report an error if the last line read was illegal. */ if( bad ) { *status = SAI__ERROR; msgSeti( "I", iline ); errRep( "", "Illegal line found in old steps file (line ^I):", status ); msgSetc( "L", buf ); errRep( "", "'^L'", status ); /* Report an error if the number of steps in the old file is still unknown */ } else if( nold == -1 ) { *status = SAI__ERROR; errRep( "", "Required line not found in old steps file:", status ); errRep( "", "'# Number of steps fixed = ...'", status ); /* Report an error if the number of lines of tabular data was wrong. */ } else if( istep != nold ) { *status = SAI__ERROR; errRep( "", "Incorrect number of step descriptions in old steps file.", status ); msgSeti( "I", istep ); msgSeti( "N", nold ); errRep( "", "Header says file contains ^N steps but data for ^I " "steps was found.", status ); } return result; }
/* Main entry */ void smurf_fixsteps( int *status ) { /* Local Variables */ AstKeyMap *keymap; /* Default config parameter values */ AstKeyMap *sub_instruments; /* Info about sub-instruments */ FILE *fd = NULL; /* File descriptor */ Grp *igrp = NULL; /* Input group of files */ Grp *ogrp = NULL; /* Output group of files */ dim_t dcfitbox; /* DCFITBOX config parameter */ dim_t dcsmooth; /* DCSMOOTH config parameter */ dim_t nx; /* Length of first pixel axis */ double dcthresh; /* DCTHRESH config parameter */ double sizetol; /* Tolerance allowed on step height */ int changed; /* Have any step fixes changed? */ int dclimcorr; /* DCLIMCORR config parameter */ int dcmaxsteps; /* DCMAXSTEPS config parameter */ int first; /* Index of first change to report */ int itemp; /* Intermediate value */ int meanshift; /* Use a mean shift filter? */ int nnew; /* Number of new step fixes */ int nold; /* Number of old step fixes */ size_t nrej; /* Number of rejected bolometers */ size_t outsize; /* Total number of NDF names in the output group */ size_t size; /* Number of files in input group */ smfData *data = NULL; /* Output smfData */ smfData *indata = NULL; /* Input smfData */ smfStepFix *newsteps = NULL; /* New step fix descriptions */ smfStepFix *oldsteps = NULL; /* Old step fix descriptions */ ThrWorkForce *wf = NULL; /* Pointer to a pool of worker threads */ /* Check inherited status */ if (*status != SAI__OK) return; /* begin an NDF context. */ ndfBegin(); /* Get the name of the input NDF. */ kpg1Rgndf( "IN", 1, 1, "", &igrp, &size, status ); /* Get output file(s) */ kpg1Wgndf( "OUT", igrp, size, 0, "More output files required...", &ogrp, &outsize, status ); /* Open the input data file, read-only. */ smf_open_file( igrp, 1, "Read", 0, &indata, status ); /* Since we will be modifying the data values, we need a deep copy. */ data = smf_deepcopy_smfData( indata, 0, 0, 0, 0, status ); /* Place cleaning parameters into a keymap and set defaults. Note that we use the map-maker defaults file here so that we populate the locked keymap with all the parameters that people may come across to allow them to load their map-maker config directly this application. */ sub_instruments = smf_subinst_keymap( SMF__SUBINST_NONE, data, NULL, 0, status ); keymap = kpg1Config( "CONFIG", "$SMURF_DIR/smurf_makemap.def", sub_instruments, status ); sub_instruments = astAnnul( sub_instruments ); /* Set the default for each of the step fixing config parameters. */ astMapGet0I( keymap, "DCSMOOTH", &itemp ); parDef0i( "DCSMOOTH", itemp, status ); astMapGet0I( keymap, "DCFITBOX", &itemp ); parDef0i( "DCFITBOX", itemp, status ); astMapGet0I( keymap, "DCMAXSTEPS", &itemp ); parDef0i( "DCMAXSTEPS", itemp, status ); astMapGet0I( keymap, "DCLIMCORR", &itemp ); parDef0i( "DCLIMCORR", itemp, status ); astMapGet0D( keymap, "DCTHRESH", &dcthresh ); parDef0d( "DCTHRESH", dcthresh, status ); /* Get values for the config params */ parGet0i( "DCSMOOTH", &itemp, status ); dcsmooth = itemp; parGet0i( "DCFITBOX", &itemp, status ); dcfitbox = itemp; parGet0i( "DCMAXSTEPS", &itemp, status ); dcmaxsteps = itemp; parGet0i( "DCLIMCORR", &itemp, status ); dclimcorr = itemp; parGet0d( "DCTHRESH", &dcthresh, status ); parGet0l( "MEANSHIFT", &meanshift, status ); /* Find the number of cores/processors available and create a pool of threads of the same size. */ wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status ); /* Fix the steps. */ smf_fix_steps( wf, data, dcthresh, dcsmooth, dcfitbox, dcmaxsteps, dclimcorr, meanshift, &nrej, &newsteps, &nnew, status ); /* Display a summary of what was done by the step fixer. */ msgBlank( status ); if( nrej == 0 ) { msgOut( "", "No bolometers were rejected", status ); } else if( nrej == 1 ) { msgOut( "", "One bolometer was rejected", status ); } else { msgSeti( "NREJ", nrej ); msgOut( "", "^NREJ bolometers were rejected", status ); } parPut0i( "NREJECTED", nrej, status ); if( nnew == 0 ) { msgOut( "", "No steps were fixed", status ); } else if( nnew == 1 ) { msgOut( "", "One step was fixed", status ); } else { msgSeti( "NNEW", nnew ); msgOut( "", "^NNEW steps were fixed", status ); } parPut0i( "NFIXED", nnew, status ); /* If required, write out to a text file details of the steps that were fixed. */ fd = smf_open_textfile( "NEWSTEPS", "w", "<none>", status ); if( fd ) { smf1_write_steps( fd, indata, nnew, newsteps, dcthresh, dcsmooth, dcfitbox, dcmaxsteps, dclimcorr, nrej, status ); fclose( fd ); } /* If required, create the output NDF. */ if( outsize > 0 && indata && indata->file ) { smf_write_smfData( data, NULL, NULL, ogrp, 1, indata->file->ndfid, MSG__VERB, 0, status ); } /* Save the length of the first pixel axis. */ nx = data ? data->dims[ 0 ] : 0; /* Close the NDFs. */ smf_close_file( &data, status ); smf_close_file( &indata, status ); /* Attempt to open a file containing descriptions of steps fixed by a previous invocation of this program. */ fd = smf_open_textfile( "OLDSTEPS", "r", "<none>", status ); if( fd ) { /* Get SIZETOL - the minimum significant fractional error in step sizes. */ parGet0d( "SIZETOL", &sizetol, status ); /* Read the contents of the file, issuing a warning if the global properties read from the file (e.g. parameters used, no. of steps found, etc) differ from those of the current invocation. */ msgBlank( status ); oldsteps = smf1_read_steps( fd, dcthresh, dcsmooth, dcfitbox, dcmaxsteps, dclimcorr, nrej, nnew, &nold, status ); /* Get the index of the first change to report. */ parGet0i( "FIRST", &first, status ); /* Compare the new step fixes with the old step fixes, issuing a warning for the first step fix that has changed. */ changed = smf1_check_steps( "CONTINUE", first, nx, sizetol, nold, nnew, oldsteps, newsteps, status ); /* Store a flag indicating if any sstep fixes have chnaged. */ parPut0l( "CHANGED", changed, status ); /* Tell the user if nothing has changed. */ if( ! changed ) { msgOut( "", "There are no significant differences " "between old and new step fixes.", status ); } msgBlank( status ); /* Close the old steps file, and free the memory holding the old step descriptions. */ fclose( fd ); oldsteps = astFree( oldsteps ); } /* Free resources. */ newsteps = astFree( newsteps ); grpDelet( &igrp, status ); grpDelet( &ogrp, status ); /* End the NDF context. */ ndfEnd( status ); /* If anything went wrong issue a context message. */ if( *status != SAI__OK ) msgOutif( MSG__VERB, " ", "FIXSTEPS failed.", status ); }
void smurf_jsatileinfo( int *status ) { /* Local Variables */ AstCmpRegion *overlap; AstFitsChan *fc; AstFrameSet *fs; AstObject *obj; AstRegion *region; AstRegion *target; HDSLoc *cloc = NULL; HDSLoc *xloc = NULL; char *jcmt_tiles; char *tilendf = NULL; char text[ 200 ]; double dec[ 8 ]; double dist; double dlbnd[ 2 ]; double dubnd[ 2 ]; double gx[ 8 ]; double gy[ 8 ]; double maxdist; double norm_radec[2]; double point1[ 2 ]; double point2[ 2 ]; double ra[ 8 ]; double ra0; double dec0; int *ipntr; int axes[ 2 ]; int create; int dirlen; int el; int exists; int flag; int i; int indf1; int indf2; int indf3; int itile; int iv; int jtile; int lbnd[ 2 ]; int local_origin; int nc; int place; int tlbnd[ 2 ]; int tubnd[ 2 ]; int ubnd[ 2 ]; smf_jsaproj_t proj; int xt; int yt; smfJSATiling skytiling; void *pntr; /* Check inherited status */ if( *status != SAI__OK ) return; /* Start a new AST context. */ astBegin; /* Get the instrument to use abnd get the parameters describing the layout of its JSA tiles. */ smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &skytiling, status ); /* Return the maximum tile index. */ parPut0i( "MAXTILE", skytiling.ntiles - 1, status ); /* Abort if an error has occurred. */ if( *status != SAI__OK ) goto L999; /* Decide what sort of projection to use. */ parChoic( "PROJ", "HPX", "HPX,HPX12,XPHN,XPHS", 1, text, sizeof(text), status ); proj = smf_jsaproj_fromstr( text, 1, status ); /* If required, create an all-sky NDF in which each pixel covers the area of a single tile, and holds the integer tile index. The NDF has an initial size of 1x1 pixels, but is expanded later to the required size. */ lbnd[ 0 ] = ubnd[ 0 ] = lbnd[ 1 ] = ubnd[ 1 ] = 1; ndfCreat( "ALLSKY", "_INTEGER", 2, lbnd, ubnd, &indf3, status ); /* If a null (!) value was supplied for parameter ALLSKY, annull the error and pass on. */ if( *status == PAR__NULL ) { errAnnul( status ); /* Otherwise, create a FrameSet describing the whole sky in which each pixel corresponds to a single tile. */ } else { smf_jsatile( -1, &skytiling, 0, proj, NULL, &fs, NULL, lbnd, ubnd, status ); /* Change the bounds of the output NDF. */ ndfSbnd( 2, lbnd, ubnd, indf3, status ); /* Store the FrameSet in the NDF. */ ndfPtwcs( fs, indf3, status ); /* Map the data array. */ ndfMap( indf3, "Data", "_INTEGER", "WRITE/BAD", (void **) &ipntr, &el, status ); /* Create all-sky map using XPH projection. */ if( *status == SAI__OK ) { /* Loop round every tile index. */ for( jtile = 0; jtile < skytiling.ntiles; jtile++ ) { /* Get the zero-based (x,y) indices of the tile within an HPX projection. This flips the bottom left half-facet up to the top right. */ smf_jsatilei2xy( jtile, &skytiling, &xt, &yt, NULL, status ); /* Convert these HPX indices to the corresponding indices within the required projection. Note, the lower left facet is split by the above call to smf_jsatilei2xy tile (i.e. (xt,yt) indices are *not* in the "raw" mode). For instance, (0,0) is not a valid tile. */ smf_jsatilexyconv( &skytiling, proj, xt, yt, 0, &xt, &yt, status ); /* Get the vector index of the corresponding element of the all-sky NDF. */ if( proj == SMF__JSA_HPX || proj == SMF__JSA_HPX12 ) { iv = xt + 5*skytiling.ntpf*yt; } else { iv = xt + 4*skytiling.ntpf*yt; } /* Report an error if this element has already been assigned a tile index. Otherwise, store the tile index. */ if( ipntr[ iv ] == VAL__BADI ) { ipntr[ iv ] = jtile; } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRepf( "", "%s projection assigns multiple tiles to " "pixel (%d,%d).", status, text, xt, yt ); break; } } } /* Store NDF title. */ sprintf( text, "JSA tile indices for %s data", skytiling.name ); ndfCput( text, indf3, "TITLE", status ); /* Store the instrument as a component in the SMURF extension. */ ndfXnew( indf3, "SMURF", "INSTRUMENT", 0, 0, &xloc, status ); ndfXpt0c( skytiling.name, indf3, "SMURF", "INSTRUMENT", status ); datAnnul( &xloc, status ); /* Close the NDF. */ ndfAnnul( &indf3, status ); } /* Abort if an error has occurred. */ if( *status != SAI__OK ) goto L999; /* Get the zero-based index of the required tile. If a null value is supplied, annull the error and skip to the end. */ parGdr0i( "ITILE", 0, 0, skytiling.ntiles - 1, 0, &itile, status ); if( *status == PAR__NULL ) { errAnnul( status ); goto L999; } /* See if the pixel origin is to be at the centre of the tile. */ parGet0l( "LOCAL", &local_origin, status ); /* Display the tile number. */ msgBlank( status ); msgSeti( "ITILE", itile ); msgSeti( "MAXTILE", skytiling.ntiles - 1); msgOut( " ", " Tile ^ITILE (from 0 to ^MAXTILE):", status ); /* Get the FITS header, FrameSet and Region defining the tile, and the tile bounds in pixel indices. */ smf_jsatile( itile, &skytiling, local_origin, proj, &fc, &fs, ®ion, lbnd, ubnd, status ); /* Write the FITS headers out to a file, annulling the error if the header is not required. */ if( *status == SAI__OK ) { atlDumpFits( "HEADER", fc, status ); if( *status == PAR__NULL ) errAnnul( status ); } /* If required, write the Region out to a text file. */ if( *status == SAI__OK ) { atlCreat( "REGION", (AstObject *) region, status ); if( *status == PAR__NULL ) errAnnul( status ); } /* Store the lower and upper pixel bounds of the tile. */ parPut1i( "LBND", 2, lbnd, status ); parPut1i( "UBND", 2, ubnd, status ); /* Display pixel bounds on the screen. */ msgSeti( "XL", lbnd[ 0 ] ); msgSeti( "XU", ubnd[ 0 ] ); msgSeti( "YL", lbnd[ 1 ] ); msgSeti( "YU", ubnd[ 1 ] ); msgOut( " ", " Pixel bounds: (^XL:^XU,^YL:^YU)", status ); /* Get the RA,Dec at the tile centre. */ if( astTest( fs, "SkyRef" ) ) { ra0 = astGetD( fs, "SkyRef(1)" ); dec0 = astGetD( fs, "SkyRef(2)" ); /* Format the central RA and Dec. and display. Call astNorm on the coordinates provided that the frame set has the correct number of axes (which it should as it comes from smf_jsatile). */ norm_radec[0] = ra0; norm_radec[1] = dec0; if (astGetI(fs, "Naxes") == 2) astNorm(fs, norm_radec); msgSetc( "RACEN", astFormat( fs, 1, norm_radec[ 0 ] )); msgSetc( "DECCEN", astFormat( fs, 2, norm_radec[ 1 ] )); msgOut( " ", " Centre (ICRS): RA=^RACEN DEC=^DECCEN", status ); /* Transform a collection of points on the edge of the region (corners and side mid-points) from GRID coords to RA,Dec. */ point1[ 0 ] = 0.5; point1[ 1 ] = 0.5; point2[ 0 ] = ubnd[ 0 ] - lbnd[ 0 ] + 1; point2[ 1 ] = ubnd[ 1 ] - lbnd[ 1 ] + 1; gx[ 0 ] = point1[ 0 ]; /* Bottom left */ gy[ 0 ] = point1[ 1 ]; gx[ 1 ] = point1[ 0 ]; /* Centre left */ gy[ 1 ] = gy[ 0 ]; gx[ 2 ] = point1[ 0 ]; /* Top left */ gy[ 2 ] = point2[ 1 ]; gx[ 3 ] = gx[ 0 ]; /* Top centre */ gy[ 3 ] = point2[ 1 ]; gx[ 4 ] = point2[ 0 ]; /* Top right */ gy[ 4 ] = point2[ 1 ]; gx[ 5 ] = point2[ 0 ]; /* Centre right */ gy[ 5 ] = gy[ 0 ]; gx[ 6 ] = point2[ 0 ]; /* Bottom right */ gy[ 6 ] = point1[ 1 ]; gx[ 7 ] = gx[ 0 ]; /* Bottom centre */ gy[ 7 ] = point1[ 1 ]; astTran2( fs, 8, gx, gy, 1, ra, dec ); /* Find the arc-distance from the centre to the furthest point from the centre. */ point1[ 0 ] = ra0; point1[ 1 ] = dec0; maxdist = -1.0; for( i = 1; i < 8; i++ ) { if( ra[ i ] != AST__BAD && dec[ i ] != AST__BAD ) { point2[ 0 ] = ra[ i ]; point2[ 1 ] = dec[ i ]; dist = astDistance( fs, point1, point2 ); if( dist > maxdist ) maxdist = dist; } } /* Convert from radius to diameter. */ maxdist *= 2.0; /* Format this size as a dec value (i.e. arc-distance) and display it. */ if( maxdist > 0.0 ) { msgSetc( "SIZE", astFormat( fs, 2, maxdist ) ); msgOut( " ", " Size: ^SIZE", status ); } else { maxdist = AST__BAD; msgOut( " ", " Size: <unknown>", status ); } /* If a discontinuity passes through the tile, the centre and size may be unknown. */ } else { ra0 = AST__BAD; dec0 = AST__BAD; maxdist = AST__BAD; msgOut( " ", " Centre (ICRS): RA=<unknown> DEC=<unknown>", status ); msgOut( " ", " Size: <unknown>", status ); } /* Write the tile centre ra and dec in radians to the output parameters. */ parPut0d( "RACEN", norm_radec[ 0 ], status ); parPut0d( "DECCEN", norm_radec[ 1 ], status ); /* Write the size to the output parameter as radians. */ parPut0d( "SIZE", maxdist, status ); /* Get the translation of the environment variable JSA_TILE_DIR. */ jcmt_tiles = getenv( "JSA_TILE_DIR" ); /* Initialise the path to the tile's NDF to hold the root directory. Use the current working directory if JSA_TILE_DIR is undefined. */ if( jcmt_tiles ) { nc = 0; tilendf = astAppendString( tilendf, &nc, jcmt_tiles ); } else { nc = 512; jcmt_tiles = astMalloc( nc ); while( !getcwd( jcmt_tiles, nc ) ) { nc *= 2; jcmt_tiles = astRealloc( jcmt_tiles, nc ); } nc = 0; tilendf = astAppendString( tilendf, &nc, jcmt_tiles ); jcmt_tiles = astFree( jcmt_tiles ); } /* Complete the path to the tile's NDF. */ tilendf = astAppendString( tilendf, &nc, "/" ); tilendf = astAppendString( tilendf, &nc, skytiling.subdir ); dirlen = nc; sprintf( text, "/tile_%d.sdf", itile ); tilendf = astAppendString( tilendf, &nc, text ); /* Write it to the output parameter. */ parPut0c( "TILENDF", tilendf, status ); /* See if the NDF exists, and store the flag in the output parameter. */ exists = access( tilendf, F_OK ) ? 0 : 1; parPut0l( "EXISTS", exists, status ); /* If the NDF does not exist, create it if required. */ parGet0l( "CREATE", &create, status ); if( !exists && create && *status == SAI__OK ) { /* Write the NDF info to the screen. */ msgSetc( "NDF", tilendf ); msgOutif( MSG__NORM, " ", " NDF: ^NDF (created)", status ); /* Temporarily terminate the NDF path at the end of the subdirectory. */ tilendf[ dirlen ] = 0; /* Create the required directory (does nothing if the directory already exists). It is given read/write/search permissions for owner and group, and read/search permissions for others. */ (void) mkdir( tilendf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); /* Replace the character temporarily overwritten above. */ tilendf[ dirlen ] = '/'; /* Now create the tile's NDF. */ ndfPlace( NULL, tilendf, &place, status ); ndfNew( skytiling.type, 2, lbnd, ubnd, &place, &indf1, status ); /* Fill its data array with zeros. */ ndfMap( indf1, "Data", skytiling.type, "WRITE/ZERO", &pntr, &el, status ); /* Store the WCS FrameSet. */ ndfPtwcs( fs, indf1, status ); /* If the instrument jsatiles.have variance, fill the variance array with zeros. */ if( skytiling.var ) { ndfMap( indf1, "Variance", skytiling.type, "WRITE/ZERO", &pntr, &el, status ); } /* Create a SMURF extension. */ ndfXnew( indf1, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &xloc, status ); /* Store the tile number and instrument name in the extension. */ datNew0I( xloc, "TILE", status ); datFind( xloc, "TILE", &cloc, status ); datPut0I( cloc, itile, status ); datAnnul( &cloc, status ); datNew0C( xloc, "INSTRUMENT", strlen( skytiling.name ), status ); datFind( xloc, "INSTRUMENT", &cloc, status ); datPut0C( cloc, skytiling.name, status ); datAnnul( &cloc, status ); /* Create a weights NDF within the SMURF extension, and fill its data array with zeros. */ ndfPlace( xloc, "WEIGHTS", &place, status ); ndfNew( skytiling.type, 2, lbnd, ubnd, &place, &indf2, status ); ndfMap( indf2, "Data", skytiling.type, "WRITE/ZERO", &pntr, &el, status ); ndfPtwcs( fs, indf2, status ); ndfAnnul( &indf2, status ); /* Annul the extension locator and the main NDF identifier. */ datAnnul( &xloc, status ); ndfAnnul( &indf1, status ); /* Write the NDF info to the screen. */ } else { msgSetc( "NDF", tilendf ); msgSetc( "E", exists ? "exists" : "does not exist" ); msgOut( " ", " NDF: ^NDF (^E)", status ); } /* Initialise TBND and TLBND to indicate no overlap. */ tlbnd[ 0 ] = 1; tlbnd[ 1 ] = 1; tubnd[ 0 ] = 0; tubnd[ 1 ] = 0; /* Attempt to to get an AST Region (assumed to be in some 2D sky coordinate system) using parameter "TARGET". */ if( *status == SAI__OK ) { kpg1Gtobj( "TARGET", "Region", (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion), &obj, status ); /* Annul the error if none was obtained. */ if( *status == PAR__NULL ) { errAnnul( status ); /* Otherwise, use the supplied object. */ } else { target = (AstRegion *) obj; /* If the target Region is 3-dimensional, remove the third axis, which is assumed to be a spectral axis. */ if( astGetI( target, "Naxes" ) == 3 ) { axes[ 0 ] = 1; axes[ 1 ] = 2; target = astPickAxes( target, 2, axes, NULL ); } /* See if there is any overlap between the target and the tile. */ overlap = NULL; flag = astOverlap( region, target ); if( flag == 0 ) { msgOut( "", " Cannot convert between the coordinate system of the " "supplied target and the tile.", status ); } else if( flag == 1 || flag == 6 ) { msgOut( "", " There is no overlap between the target and the tile.", status ); } else if( flag == 2 ) { msgOut( "", " The tile is contained within the target.", status ); tlbnd[ 0 ] = lbnd[ 0 ]; tlbnd[ 1 ] = lbnd[ 1 ]; tubnd[ 0 ] = ubnd[ 0 ]; tubnd[ 1 ] = ubnd[ 1 ]; } else if( flag == 3 ) { overlap = astCmpRegion( region, target, AST__AND, " " ); } else if( flag == 4 ) { overlap = astCmpRegion( region, target, AST__AND, " " ); } else if( flag == 5 ) { msgOut( "", " The target and tile are identical.", status ); tlbnd[ 0 ] = lbnd[ 0 ]; tlbnd[ 1 ] = lbnd[ 1 ]; tubnd[ 0 ] = ubnd[ 0 ]; tubnd[ 1 ] = ubnd[ 1 ]; } else if( *status == SAI__OK ) { *status = SAI__OK; errRepf( "", "Unexpected value %d returned by astOverlap " "(programming error).", status, flag ); } /* If a region containing the intersection of the tile and target was created above, map it into the grid coordinate system of the tile. */ if( overlap ) { overlap = astMapRegion( overlap, astGetMapping( fs, AST__CURRENT, AST__BASE ), astGetFrame( fs, AST__BASE ) ); /* Get its GRID bounds. */ astGetRegionBounds( overlap, dlbnd, dubnd ); /* Convert to integer. */ tlbnd[ 0 ] = ceil( dlbnd[ 0 ] - 0.5 ); tlbnd[ 1 ] = ceil( dlbnd[ 1 ] - 0.5 ); tubnd[ 0 ] = ceil( dubnd[ 0 ] - 0.5 ); tubnd[ 1 ] = ceil( dubnd[ 1 ] - 0.5 ); /* Convert to PIXEL indices within the tile. */ tlbnd[ 0 ] += lbnd[ 0 ] - 1; tlbnd[ 1 ] += lbnd[ 1 ] - 1; tubnd[ 0 ] += lbnd[ 0 ] - 1; tubnd[ 1 ] += lbnd[ 1 ] - 1; msgOutf( "", " The target overlaps section (%d:%d,%d:%d).", status, tlbnd[ 0 ], tubnd[ 0 ], tlbnd[ 1 ], tubnd[ 1 ] ); } } } /* Store the pixel index bounds of the tiles overlap with the target. */ parPut1i( "TLBND", 2, tlbnd, status ); parPut1i( "TUBND", 2, tubnd, status ); /* Arrive here if an error occurs. */ L999:; /* Free resources. */ tilendf = astFree( tilendf ); /* End the AST context. */ astEnd; /* Issue a status indication.*/ msgBlank( status ); if( *status == SAI__OK ) { msgOutif( MSG__VERB, "", "JSATILEINFO succeeded.", status); } else { msgOutif( MSG__VERB, "", "JSATILEINFO failed.", status); } }
void smf_calc_iqu( ThrWorkForce *wf, smfData *data, int block_start, int block_end, int ipolcrd, int qplace, int uplace, int iplace, NdgProvenance *oprov, AstFitsChan *fc, int pasign, double paoff, double angrot, int submean, int harmonic, int *status ){ /* Local Variables: */ AstCmpMap *cm1; AstCmpMap *cm2; AstFrameSet *wcs; /* WCS FrameSet for output NDFs */ AstMapping *fpmap1; AstMapping *fpmap2; AstMapping *oskymap; AstMapping *totmap; AstSkyFrame *oskyfrm; AstWinMap *wm; /* Mapping to reverse the X GRID axis */ const JCMTState *state; /* JCMTState info for current time slice */ const char *usesys; /* Used system string */ dim_t itime; /* Time slice index */ dim_t nbolo; /* No. of bolometers */ dim_t ncol; /* No. of columns of bolometers */ dim_t nrow; /* No. of rows of bolometers */ dim_t ntime; /* Time slices to check */ dim_t ntslice; /* Number of time-slices in data */ double *ipi; /* Pointer to output I array */ double *ipiv; /* Pointer to output I variance array */ double *ipq; /* Pointer to output Q array */ double *ipqv; /* Pointer to output Q variance array */ double *ipu; /* Pointer to output U array */ double *ipuv; /* Pointer to output U variance array */ double *mean; double ang_data[2]; double fox[2]; double foy[2]; double fpr0; double fprinc; double fx[2]; double fy[2]; double ina[ 2 ]; /* Bolometer coords at bottom left */ double inb[ 2 ]; /* Bolometer coords at top right */ double outa[ 2 ]; /* NDF GRID coords at bottom left */ double outb[ 2 ]; /* NDF GRID coords at top right */ int bstep; /* Bolometer step between threads */ int el; /* Number of mapped array elements */ int gotvar; /* Were any output variances created? */ int indfi; /* Identifier for NDF holding I values */ int indfq; /* Identifier for NDF holding Q values */ int indfu; /* Identifier for NDF holding Q values */ int iworker; /* Index of a worker thread */ int lbnd[ 2 ]; /* Lower pixel bounds of output NDF */ int moving; int nworker; /* No. of worker threads */ int old; /* Data has old-style POL_ANG values? */ int tstep; /* Time slice step between threads */ int ubnd[ 2 ]; /* Upper pixel bounds of output NDF */ size_t bstride; /* Stride between adjacent bolometer values */ size_t tstride; /* Stride between adjacent time slice values */ smfCalcIQUJobData *job_data = NULL; /* Pointer to all job data */ smfCalcIQUJobData *pdata = NULL;/* Pointer to next job data */ smfHead *hdr; /* Pointer to data header this time slice */ /* Check the inherited status. */ if( *status != SAI__OK ) return; /* Convenience pointers. */ hdr = data->hdr; /* Obtain number of time slices - will also check for 3d-ness. Also get the dimensions of the bolometer array and the strides between adjacent bolometer values. */ smf_get_dims( data, &nrow, &ncol, &nbolo, &ntslice, NULL, &bstride, &tstride, status ); /* Report an error if the block of time slices extends of either end. */ if( block_start < 0 || block_end >= (int) ntslice ) { if( *status == SAI__OK ) { *status = SAI__ERROR; msgSeti( "S", block_start ); msgSeti( "E", block_end ); msgSeti( "N", ntslice ); errRep( " ", "smf_calc_iqu: invalid block of time slices - ^S to " "^E (^N time slices are available).", status ); } } /* Create the output NDFs. Each one is a 2D array with dimensions equal to the bolometer array. */ lbnd[ 0 ] = 1; lbnd[ 1 ] = 1; ubnd[ 0 ] = ncol; ubnd[ 1 ] = nrow; ndfNew( "_DOUBLE", 2, lbnd, ubnd, &qplace, &indfq, status ); ndfNew( "_DOUBLE", 2, lbnd, ubnd, &uplace, &indfu, status ); if( iplace != NDF__NOPL ) { ndfNew( "_DOUBLE", 2, lbnd, ubnd, &iplace, &indfi, status ); } else { indfi = NDF__NOID; } /* Store any supplied provenance in all NDFs. */ if( oprov ) { ndgWriteProv( oprov, indfq, 1, status ); ndgWriteProv( oprov, indfu, 1, status ); if( indfi != NDF__NOID ) ndgWriteProv( oprov, indfi, 1, status ); } /* Store any supplied FITS headers in all NDFs.*/ if( fc && astGetI( fc, "NCard" ) > 0 ) { kpgPtfts( indfq, fc, status ); kpgPtfts( indfu, fc, status ); if( indfi != NDF__NOID ) kpgPtfts( indfi, fc, status ); } /* Store the WCS frameSet in all NDFs. First get the FrameSet for the central time slice in the block, and set its current Frame to the tracking frame. */ smf_tslice_ast( data, ( block_start + block_end )/2, 1, NO_FTS, status); usesys = sc2ast_convert_system( (data->hdr->allState)[0].tcs_tr_sys, status ); astSetC( hdr->wcs, "System", usesys ); /* Get the Mapping from focal plane coords to bolometer grid coords. This is the same for all time slices. sc2ast ensures that frame 3 is FPLANE. */ fpmap1 = astGetMapping( hdr->wcs, 3, AST__BASE ); /* Take a copy and then reverse the X axis of the GRID Frame by remaping the base Frame using a WinMap. This produces a pixel grid such as you would see by looking up at the sky from underneath the array, rather than looking down at the ground from above the array. */ wcs = astCopy( hdr->wcs ); ina[ 0 ] = 1.0; inb[ 0 ] = ncol; ina[ 1 ] = 1.0; inb[ 1 ] = nrow; outa[ 0 ] = ncol; outb[ 0 ] = 1.0; outa[ 1 ] = 1.0; outb[ 1 ] = nrow; wm = astWinMap( 2, ina, inb, outa, outb, " " ); astRemapFrame( wcs, AST__BASE, wm ); wm = astAnnul( wm ); /* Get the Mapping from output grid coords to focal plane coords. */ fpmap2 = astGetMapping( wcs, AST__BASE, 3 ); /* If the target is moving (assumed to be the case if the tracking system is AZEL or GAPPT), make the FrameSet current Frame represent offsets from the reference position (i.e. the moving target), and indicate that the offset coord system should be used for alignment. */ if( !strcmp( usesys, "AZEL" ) || !strcmp( usesys, "GAPPT" ) ){ astSet( wcs, "SkyRefIs=Origin,AlignOffset=1" ); moving = 1; } else { moving = 0; } /* Store the FrameSet in the output NDFs. */ ndfPtwcs( wcs, indfq, status ); ndfPtwcs( wcs, indfu, status ); if( indfi != NDF__NOID ) ndfPtwcs( wcs, indfi, status ); /* Map the Data array in each NDF. */ ndfMap( indfq, "Data", "_DOUBLE", "WRITE", (void **) &ipq, &el, status ); ndfMap( indfu, "Data", "_DOUBLE", "WRITE", (void **) &ipu, &el, status ); if( indfi != NDF__NOID ) { ndfMap( indfi, "Data", "_DOUBLE", "WRITE", (void **) &ipi, &el, status ); } else { ipi = NULL; } /* Map the Variance array in each NDF. */ ndfMap( indfq, "Variance", "_DOUBLE", "WRITE", (void **) &ipqv, &el, status ); ndfMap( indfu, "Variance", "_DOUBLE", "WRITE", (void **) &ipuv, &el, status ); if( indfi != NDF__NOID ) { ndfMap( indfi, "Variance", "_DOUBLE", "WRITE", (void **) &ipiv, &el, status ); } else { ipiv = NULL; } /* If required, allocate memory to hold the mean bolometer value at each time slice. */ mean = submean ? astMalloc( ntslice*sizeof( *mean ) ) : NULL; /* Create structures used to pass information to the worker threads. */ nworker = wf ? wf->nworker : 1; job_data = astMalloc( nworker*sizeof( *job_data ) ); /* Check the above pointers can be used safely. */ if( *status == SAI__OK ) { /* Go through the first thousand POL_ANG values to see if they are in units of radians (new data) or arbitrary encoder units (old data). They are assumed to be in radians if no POL_ANG value is larger than 20. */ old = 0; state = hdr->allState; ntime = ( ntslice > 1000 ) ? 1000 : ntslice; for( itime = 0; itime < ntime; itime++,state++ ) { if( state->pol_ang > 20 ) { old = 1; msgOutif( MSG__VERB, ""," POL2 data contains POL_ANG values " "in encoder units - converting to radians.", status ); break; } } /* If required, find the mean bolometer value at each time slice. */ if( submean ) { /* Determine which time-slices are to be processed by which threads. */ tstep = ntslice/nworker; if( tstep < 1 ) tstep = 1; for( iworker = 0; iworker < nworker; iworker++ ) { pdata = job_data + iworker; pdata->block_start = iworker*tstep; if( iworker < nworker - 1 ) { pdata->block_end = pdata->block_start + tstep - 1; } else { pdata->block_end = ntslice - 1; } } /* Store all the other info needed by the worker threads, and submit the jobs to calculate the Q and U values in each bolo, and then wait for them to complete. */ for( iworker = 0; iworker < nworker; iworker++ ) { pdata = job_data + iworker; pdata->bstride = bstride; pdata->dat = data->pntr[0]; pdata->nbolo = nbolo; pdata->qua = smf_select_qualpntr( data, NULL, status );; pdata->tstride = tstride; pdata->mean = mean; pdata->action = 1; /* Pass the job to the workforce for execution. */ thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL, status ); } /* Wait for the workforce to complete all jobs. */ thrWait( wf, status ); } /* Get the Frame representing absolute sky coords in the output NDF, and the Mapping from sky to grid in the output NDF. */ oskyfrm = astCopy( astGetFrame( wcs, AST__CURRENT ) ); astSet( oskyfrm, "SkyRefIs=Ignored" ); oskymap = astGetMapping( wcs, AST__CURRENT, AST__BASE ); wcs = astAnnul( wcs ); /* Find the first and last time slices, calculate the angle between the focal pane Y axis at the time slice, and the focal plane Y axis in the output NDF. For intervening time-slices, the angle is found by linear interpolation between the extreme time slices. */ for( el = 0; el < 2; el++ ) { /* Get the mapping from GRID coords in the input time slice to GRID coords in the output. */ totmap = smf_rebin_totmap( data, el?ntslice-1:0, oskyfrm, oskymap, moving, NO_FTS, status ); /* Modify it to be the Mapping from focal plane coords in the input time slice to focal plane coords in the output. */ cm1 = astCmpMap( fpmap1, totmap, 1, " " ); cm2 = astCmpMap( cm1, fpmap2, 1, " " ); /* Use this Mapping to convert two points on the focal plane Y axis from the input to the output. */ fx[0] = 0.0; fy[0] = 0.0; fx[1] = 0.0; fy[1] = 4.0; astTran2( cm2, 2, fx, fy, 1, fox, foy ); /* The angle from the focal plane Y axis in the output to the focal plane Y axis in the input time slice, measured positive in sense of rotation from Fy to Fx. */ ang_data[ el ] = atan2( fox[1]-fox[0], foy[1]-foy[0] ); /* Free resources for this time slice. */ totmap = astAnnul( totmap ); cm1 = astAnnul( cm1 ); cm2 = astAnnul( cm2 ); } /* Annul objects. */ oskymap = astAnnul( oskymap ); oskyfrm = astAnnul( oskyfrm ); fpmap1 = astAnnul( fpmap1 ); fpmap2 = astAnnul( fpmap2 ); /* Get the constants of the linear relationship between focal plane rotation and time slice index "fpr = fpr0 + itime*fprinc". */ fpr0 = ang_data[ 0 ]; fprinc = ( ang_data[ 1 ] - fpr0 )/( ntslice - 1 ); /* Determine which bolometers are to be processed by which threads. */ bstep = nbolo/nworker; if( bstep < 1 ) bstep = 1; for( iworker = 0; iworker < nworker; iworker++ ) { pdata = job_data + iworker; pdata->b1 = iworker*bstep; pdata->b2 = pdata->b1 + bstep - 1; } /* Ensure that the last thread picks up any left-over bolometers */ pdata->b2 = nbolo - 1; /* Store all the other info needed by the worker threads, and submit the jobs to calculate the Q and U values in each bolo, and then wait for them to complete. */ for( iworker = 0; iworker < nworker; iworker++ ) { pdata = job_data + iworker; pdata->bstride = bstride; pdata->dat = data->pntr[0];; pdata->nbolo = nbolo; pdata->qua = smf_select_qualpntr( data, NULL, status );; pdata->tstride = tstride; pdata->allstates = hdr->allState; pdata->ipq = ipq; pdata->ipu = ipu; pdata->ipi = ipi; pdata->ipqv = ipqv; pdata->ipuv = ipuv; pdata->ipiv = ipiv; pdata->ipolcrd = ipolcrd; pdata->block_start = block_start; pdata->block_end = block_end; pdata->old = old; pdata->ncol = ncol; pdata->pasign = pasign ? +1: -1; pdata->paoff = paoff; pdata->angrot = angrot; pdata->fpr0 = fpr0; pdata->fprinc = fprinc; pdata->angfac = harmonic/4.0; pdata->action = 0; pdata->mean = mean; /* Pass the job to the workforce for execution. */ thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL, status ); } /* Wait for the workforce to complete all jobs. */ thrWait( wf, status ); /* See if any thread produced non-bad variance values. */ gotvar = 0; for( iworker = 0; iworker < nworker; iworker++ ) { pdata = job_data + iworker; if( pdata->gotvar ) gotvar = 1; } /* If no variances were created, erase the Variance component and tell the user. */ ndfUnmap( indfq, "*", status ); ndfUnmap( indfu, "*", status ); if( ipi ) ndfUnmap( indfi, "*", status ); if( !gotvar ) { ndfReset( indfq, "Variance", status ); ndfReset( indfu, "Variance", status ); if( ipi ) ndfReset( indfi, "Variance", status ); msgOut( "", "Warning: Insufficient input data to produce variances", status ); } } /* Add POLANAL Frames to the WCS FrameSet in each output NDF. This Frame is used by POLPACK to determine the reference direction of the Stokes vectors (focal plane Y in this case, i.e. zero-based axis 1 ). */ smf_polext( indfq, 0, 0.0, "FPLANE", 1, status ); smf_polext( indfu, 0, 0.0, "FPLANE", 1, status ); if( ipi ) smf_polext( indfi, 0, 0.0, "FPLANE", 1, status ); /* Free the two output NDFs. */ ndfAnnul( &indfq, status ); ndfAnnul( &indfu, status ); if( ipi ) ndfAnnul( &indfi, status ); /* Free other resources. */ job_data = astFree( job_data ); mean = astFree( mean ); }
F77_SUBROUTINE(configecho)( INTEGER(STATUS) ){ /* *+ * Name: * CONFIGECHO * Purpose: * Displays one or more configuration parameters. * Language: * C (designed to be called from Fortran) * Type of Module: * ADAM A-task * Invocation: * CALL CONFIGECHO( STATUS ) * Arguments: * STATUS = INTEGER (Given and Returned) * The global status. * Description: * This application displays the name and value of one or all * configuration parameters, specified using Parameters CONFIG or * NDF. If a single parameter is displayed, its value is also * written to an output parameter. If the parameter value is not * specified by the CONFIG, NDF or DEFAULTS parameter, then the * value supplied for DEFVAL is displayed. * * If an input NDF is supplied then configuration parameters * are read from its history (see Parameters NDF and APPLICATION). * * If values are supplied for both CONFIG and NDF, then the * differences between the two sets of configuration parameters * are displayed (see Parameter NDF). * Usage: * configecho name config [defaults] [select] [defval] * ADAM Parameters: * APPLICATION = LITERAL (Read) * When reading configuration parameters from the history * of an NDF, this parameter specifies the name of the application * to find in the history. There must be a history component * corresponding to the value of this parameter, and it must * include a CONFIG group. [current value] * CONFIG = GROUP (Read) * Specifies values for the configuration parameters. If the string * "def" (case-insensitive) or a null (!) value is supplied, the * configuration parameters are obtained using Parameter NDF. If * a null value is also supplied for NDF, a set of default * configuration parameter values will be used, as specified by * Parameter DEFAULTS. * * The supplied value should be either a comma-separated list of * strings or the name of a text file preceded by an up-arrow * character "^", containing one or more comma-separated lists of * strings. Each string is either a "keyword=value" setting, or the * name of a text file preceded by an up-arrow character "^". Such * text files should contain further comma-separated lists which * will be read and interpreted in the same manner (any blank lines * or lines beginning with "#" are ignored). Within a text file, * newlines can be used as delimiters, as well as commas. Settings * are applied in the order in which they occur within the list, * with later settings overriding any earlier settings given for * the same keyword. * * Each individual setting should be of the form "<keyword>=<value>". * If a non-null value is supplied for Parameter DEFAULTS, an error * will be reported if CONFIG includes values for any parameters * that are not included in DEFAULTS. * DEFAULTS = LITERAL (Read) * The path to a file containing the default value for every * allowed configuration parameter. If null (!) is supplied, no * defaults will be supplied for parameters that are not specified * by CONFIG, and no tests will be performed on the validity of * paramter names supplied by CONFIG. [!] * DEFVAL = LITERAL (Read) * The value to return if no value can be obtained for the named * parameter, or if the value is "<undef>". [<***>] * NAME = LITERAL (Read) * The name of the configuration parameter to display. If set to * null (!), then all parameters defined in the configuration are * displayed. * NDF = NDF (Read) * An NDF file containing history entries which include * configuration parameters. If not null (!) the history * of the NDF will be searched for a component corresponding * to the Parameter APPLICATION. The Parameter CONFIG * is then optional, but if it too is not null (!) then * the output will show the differences between the configuration * stored in the NDF history and the given configuration: * new parameters and those different from the reference * configuration (given by Parameter CONFIG) are prefixed * with "+" and those which are the same as the reference * configuration are prefixed with "-". [!] * SELECT = GROUP (Read) * A group that specifies any alternative prefixes that can be * included at the start of any parameter name. For instance, if * this group contains the two entries "450=1" and "850=0", then * either CONFIG or DEFAULTS can specify two values for any single * parameter -- one for the parameter prefixed by "450." and another * for the parameter prefixed by "850.". Thus, for instance, if * DEFAULTS defines a parameter called "filter", it could include * "450.filter=300" and "850.filter=600". The CONFIG parameter could * then either set the filter parameter for a specific prefix (as * in "450.filter=234"); or it could leave the prefix unspecified, * in which case the prefix used is the first one with a * non-zero value in SELECT (450 in the case of this example - 850 * has a value zero in SELECT). Thus the names of the items in * SELECT define the set of allowed alternative prefixes, and the * values indicate which one of these alternatives is to be used * (the first one with non-zero value). [!] * SORT = _LOGICAL (Read) * If TRUE then sort the listed parameters in to alphabetical order. * Otherwise, retain the order they have in the supplied * configuration. Only used if a null (!) value is supplied for * Parameter NAME. [FALSE] * VALUE = LITERAL (Write) * The value of the configuration parameter, or "<***>" if the * parameter has no value in CONFIG and DEFAULTS. * Examples: * configecho m81 ^myconf * Report the value of configuration parameter "m81" defined within * the file "myconf". If the file does not contain a value for * "m81", then "<***>" is displayed. * configecho type ^myconf select="m57=0,m31=1,m103=0" * Report the value of configuration parameter "type" defined within * the file "myconf". If the file does not contain a value for * "type", then the value of "m31.type" will be reported instead. If * neither is present, then "<***>" is displayed. * configecho flt.filt_edge_largescale \ * config=^/star/share/smurf/dimmconfig.lis \ * defaults=/star/bin/smurf/smurf_makemap.def \ * select="450=1,850=0" * Report the value of configuration parameter "flt.filt_edge_largescale" * defined within the file "/star/share/smurf/dimmconfig.lis", using * defaults from the file "/star/bin/smurf/smurf_makemap.def". If * dimmconfig.lis does not contain a value for "flt.filt_edge_largescale" * then it is searched for "450.flt.filt_edge_largescale" instead. An * error is reported if dimmconfig.lis contains values for any * items that are not defined in smurf_makemap.def. * configecho ndf=omc1 config=^/star/share/smurf/dimmconfig.lis \ * defaults=/star/bin/smurf/smurf_makemap.def \ * application=makemap name=! sort select="450=0,850=1" * Show how the configuration used to generate the 850um map * of OMC1 differs from the basic dimmconfig.lis file. * Copyright: * Copyright (C) 2012-3 Science & Technology Facilities Council. * All Rights Reserved. * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either Version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * Authors: * DSB: David S. Berry * GSB: Graham S. Bell * {enter_new_authors_here} * History: * 10-DEC-2012 (DSB): * Original version. * 6-FEB-2013 (DSB): * Added parameter DEFVAL. * 11-FEB-2013 (DSB): * Added parameter SORT and allow all parameters to be listed by * providing a null value for NAME. * 11-FEB-2013 (GSB): * Added ability to read configuration from history entries. * 13-FEB-2013 (DSB): * Nullify AST object pointers when the objects are annulled, * to avoid re-use of dead pointers. * 14-FEB-2013 (DSB): * Allow the SELECT feature to be used even if no DEFAULTS file is * supplied (see the new entry in the "Examples:" section). * 15-FEB-2013 (DSB): * Expand the prologue docs, and use NULL in place of zero for pointers. * 22-FEB-2013 (DSB): * Guard against seg fault in HistoryKeymap when the NDF does * not contain the required CONFIG entry in the History * component. * {enter_further_changes_here} *- */ GENPTR_INTEGER(STATUS) /* Local Variables: */ AstKeyMap *keymap2; AstKeyMap *keymap; Grp *grp = NULL; char *dot; char *pname; char defs[250]; char defval[250]; char name[250]; const char *value; const char *historyValue = NULL; int showall; int sort; size_t size; int indf = 0; int nrec; int i; char application[NDF__SZAPP]; char applicationi[NDF__SZAPP]; /* Abort if an error has already occurred. */ if( *STATUS != SAI__OK ) return; /* Begin an AST context */ astBegin; /* Get the value to return if no value can be obtained for the named parameter, of it it has a value of <undef>. */ parGet0c( "DEFVAL", defval, sizeof(defval), STATUS ); /* Get any defaults file, annuling the error if null (!) is supplied. */ if( *STATUS == SAI__OK ) { parGet0c( "DEFAULTS", defs, sizeof(defs), STATUS ); if( *STATUS == PAR__NULL ) { errAnnul( STATUS ); defs[0] = 0; } } /* Get the NDF identifier if requested. */ ndfBegin(); if (*STATUS == SAI__OK) { ndfAssoc("NDF", "READ", &indf, STATUS); if (*STATUS == PAR__NULL) { errAnnul(STATUS); indf = 0; } else { parGet0c("APPLICATION", application, sizeof(application), STATUS); /* Check now for error because the block below allowing an undefined * CONFIG clears this status otherwise. */ if (*STATUS != SAI__OK) goto L999; } } /* See if any alternate keyword prefixes are allowed, and if so determine which of the alternatices is to be displayed. */ kpg1Gtgrp( "SELECT", &grp, &size, STATUS ); if( *STATUS == PAR__NULL ) { grpDelet( &grp, STATUS ); errAnnul( STATUS ); keymap2 = NULL; } else { kpg1Kymap( grp, &keymap2, STATUS ); grpDelet( &grp, STATUS ); } /* Create a KeyMap holding the selected alternative for each keyword, and also supply defaults for any missing values (if a defaults file was supplied by the user). */ keymap = kpg1Config( "CONFIG", defs[0]?defs:NULL, keymap2, 0, STATUS ); /* Allow it to be NULL if we're reading an NDF because we'll replace keymap with historyConfig later if necessary. */ if( indf && *STATUS == PAR__NULL ) { errAnnul(STATUS); keymap = NULL; } /* Abort if an error has occurred. */ if( *STATUS != SAI__OK ) goto L999; /* Get the name of the required parameter, and convert to upper case (if supplied). If not supplied, set a flag indicating that all parameters should be displayed. */ parGet0c( "NAME", name, sizeof(name), STATUS ); if( *STATUS == PAR__NULL ) { errAnnul( STATUS ); showall = 1; } else { showall = 0; astChrCase( NULL, name, 1, 0 ); } /* Attempt to find the NDF's corresponding history record. */ if (indf && *STATUS == SAI__OK) { ndfHnrec(indf, &nrec, STATUS); for (i = 0; i < nrec; i ++) { ndfHinfo(indf, "APPLICATION", i + 1, applicationi, sizeof(applicationi), STATUS); if (! strncasecmp(application, applicationi, strlen(application))) { ndfHout(indf, i + 1, HistoryKeyMap, STATUS); break; } } if (*STATUS == SAI__OK && ! historyConfig) { *STATUS = SAI__ERROR; errRepf("CONFIGECHO_ERR", "CONFIGECHO: Failed to find %s " "configuration in NDF history.", STATUS, application); } else if (! keymap) { keymap = historyConfig; historyConfig = NULL; } } if( *STATUS == SAI__OK ) { /* First deal with cases where we are displaying a single parameter value. */ if( !showall ) { /* Loop round each section of the name that ends with a dot. */ value = defval; pname = name; dot = strchr( pname, '.' ); while( dot && keymap ) { /* Get a nested keymap with the name that occurs prior to the dot. If found, use it in place of the parent keymap. */ pname[ dot - pname ] = 0; if( astMapGet0A( keymap, pname, &keymap2 ) ) { astAnnul( keymap ); keymap = keymap2; } else { keymap = astAnnul( keymap ); } /* If historyConfig exists, do the same there. */ if (historyConfig) { if (astMapGet0A(historyConfig, pname, &keymap2)) { astAnnul(historyConfig); historyConfig = keymap2; } else { historyConfig = astAnnul(historyConfig); } } /* Re-instate the original dot, and move on to find the next dot. */ pname[ dot - pname ] = '.'; pname = dot + 1; dot = strchr( pname, '.' ); } /* Ensure no error is reported if the parameter is not found in the KeyMap. */ if( keymap ) { astClear( keymap, "KeyError" ); /* Get the parameter value as a string. */ astMapGet0C( keymap, pname, &value ); } if (historyConfig) { astClear(historyConfig, "KeyError"); astMapGet0C(historyConfig, pname, &historyValue); /* In NDF history mode we only want to return a value if it was found in the configuration from the history. */ if (historyValue) { if (strcmp(value, historyValue)) { msgOutf("", "+ %s", STATUS, historyValue); } else { msgOutf("", "- %s", STATUS, historyValue); } parPut0c("VALUE", historyValue, STATUS); } } else { /* Display it. */ msgOut( "", value, STATUS ); /* Write it to the output parameter. */ parPut0c( "VALUE", value, STATUS ); } /* Now deal with cases were we are displaying all parameter values. */ } else { /* See if the values should be sorted. */ parGet0l( "SORT", &sort, STATUS ); /* Display them. */ if (historyConfig) { DisplayKeyMap( historyConfig , sort, "", keymap, STATUS ); } else { DisplayKeyMap( keymap, sort, "", NULL, STATUS ); } } } /* Tidy up. */ L999:; /* End the AST context */ astEnd; /* Close the NDF if open. */ ndfEnd(STATUS); /* If an error has occurred, issue another error report identifying the program which has failed (i.e. this one). */ if( *STATUS != SAI__OK ) { errRep( "CONFIGECHO_ERR", "CONFIGECHO: Failed to echo configuration " "parameters.", STATUS ); } }
void smurf_sc2threadtest( int *status ) { /* Local Variables */ smfArray **res=NULL; /* array of smfArrays of test data */ smfData *data=NULL; /* Pointer to SCUBA2 data struct */ dim_t datalen; /* Number of data points */ smfFilter *filt=NULL; /* Frequency domain filter */ size_t i; /* Loop counter */ size_t j; /* Loop counter */ smfTimeChunkData *job_data=NULL; /* Array of pointers for job data */ size_t joblen; /* Number of chunks per job */ size_t k; /* Loop counter */ size_t nchunks; /* Number of chunks */ size_t nsub; /* Number of subarrays */ int nthread; /* Number of threads */ smfTimeChunkData *pdata=NULL; /* Pointer to data for single job */ int temp; /* Temporary integer */ size_t tsteps; /* How many time steps in chunk */ struct timeval tv1, tv2; /* Timers */ ThrWorkForce *wf = NULL; /* Pointer to a pool of worker threads */ double *dat=NULL; dim_t nbolo; dim_t ntslice; dim_t ndata; size_t bstride; size_t tstride; dim_t offset; if (*status != SAI__OK) return; /* Get input parameters */ parGdr0i( "NTHREAD", 1, 1, NUM__MAXI, 1, &nthread, status ); parGdr0i( "TSTEPS", 6000, 0, NUM__MAXI, 1, &temp, status ); tsteps = (size_t) temp; parGdr0i( "NCHUNKS", 1, 1, NUM__MAXI, 1, &temp, status ); nchunks = (size_t) temp; parGdr0i( "NSUB", 1, 1, 4, 1, &temp, status ); nsub = (size_t) temp; msgSeti("N",nthread); msgOut( "", TASK_NAME ": Running test with ^N threads", status ); /*** TIMER ***/ smf_timerinit( &tv1, &tv2, status ); /* Create some fake test data in the form of an array of smfArrays */ msgSeti("T",tsteps); msgSeti("C",nchunks); msgSeti("NS",nsub); msgOut( "", TASK_NAME ": Creating ^NS subarrays of data with ^C chunks * ^T samples", status ); res = astCalloc( nchunks, sizeof(*res) ); for( k=0; (*status==SAI__OK)&&(k<nchunks); k++ ) { res[k] = smf_create_smfArray( status ); for( i=0; (*status==SAI__OK)&&(i<nsub); i++ ) { /* Create individual smfDatas and add to array */ data = smf_create_smfData( SMF__NOCREATE_FILE | SMF__NOCREATE_DA | SMF__NOCREATE_FTS, status ); if( *status==SAI__OK ) { data->dtype=SMF__DOUBLE; data->ndims=3; data->dims[0]=40; data->dims[1]=32; data->dims[2]=(dim_t) tsteps; datalen=1; data->isFFT=-1; for( j=0; j<data->ndims; j++ ) datalen *= data->dims[j]; data->hdr->steptime = 0.005; data->pntr[0] = astCalloc( datalen, smf_dtype_sz(data->dtype,status) ); data->qual = astCalloc( datalen, sizeof(*data->qual) ); } smf_addto_smfArray( res[k], data, status ); } } /*** TIMER ***/ msgOutf( "", "** %f seconds generating data", status, smf_timerupdate(&tv1,&tv2,status) ); msgOut( "", TASK_NAME ": Starting test 1 __parallel time: dataOrder__", status ); /* Create a pool of threads. */ wf = thrGetWorkforce( nthread, status ); /* Work out number of chunks per thread */ joblen = nchunks/nthread; if( joblen == 0 ) joblen = 1; /* At least one chunk per thread */ /* The first test will process separate time chunks of data in parallel, re-ordering each to bolo-ordered format. All subarrays and an integer number of input file chunks all go into a single thread. Start by allocating and initializing a number of smfTimeChunkData's that hold the information required for each thread */ job_data = astCalloc( nthread, sizeof(*job_data) ); for( i=0; (i<(size_t)nthread) && (*status==SAI__OK); i++ ) { pdata = job_data + i; pdata->type = 0; /* Start with a data re-order */ pdata->data = res; /* Pointer to main data array */ pdata->chunk1 = i*joblen; /* Index of first chunk for job */ pdata->nchunks = nchunks; /* Total number of time chunks in data */ pdata->ijob = -1; /* Flag job as available to do work */ /* The last thread has to pick up the remainder of chunks */ if( i==(size_t)(nthread-1) ) pdata->chunk2=nchunks-1; else pdata->chunk2 = (i+1)*joblen-1; /* Index of last chunk for job */ /* Ensure a valid chunk range, or set to a length that we know to ignore */ if( pdata->chunk1 >= nchunks ) { pdata->chunk1 = nchunks; pdata->chunk2 = nchunks; } else if( pdata->chunk2 >= nchunks ) { pdata->chunk2 = nchunks-1; } if( pdata->chunk1 >= nchunks ) { /* Nothing for this thread to do */ msgSeti( "W", i+1); msgOutif( MSG__DEBUG, "", "-- parallel time: skipping thread ^W, nothing to do", status); } else { /* Since we know there is one job_data per thread, just submit jobs immediately */ pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfParallelTime, 0, NULL, status ); } } /* Wait until all of the submitted jobs have completed */ thrWait( wf, status ); /* Annul the bad status that we set in smfParallelTime */ if( *status == SMF__INSMP ) { errAnnul( status ); msgOut( "", " *** Annulled SMF__INSMP set in smfParallelTime *** ", status ); } else { msgOut( "", " *** Flushing good status *** ", status ); errFlush( status ); } /*** TIMER ***/ msgOutf( "", "** %f seconds to complete test", status, smf_timerupdate(&tv1,&tv2,status) ); /* The second test will boxcar smooth bolometers from time chunks in parallel */ msgOut( "", TASK_NAME ": Starting test 2 __parallel time: boxcar smooth__", status ); for( i=0; (i<(size_t)nthread) && (*status==SAI__OK); i++ ) { pdata = job_data + i; pdata->type = 1; /* Boxcar smooth */ if( pdata->chunk1 >= nchunks ) { /* Nothing for this thread to do */ msgSeti( "W", i+1); msgOutif( MSG__DEBUG, "", "-- parallel time: skipping thread ^W, nothing to do", status); } else { /* Since we know there is one job_data per thread, just submit jobs immediately */ pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfParallelTime, 0, NULL, status ); } } /* Wait until all of the submitted jobs have completed */ thrWait( wf, status ); /*** TIMER ***/ msgOutf( "", "** %f seconds to complete test", status, smf_timerupdate(&tv1,&tv2,status) ); msgOut( "", TASK_NAME ": *** Next 2 tests will be done twice due to FFTW planning *****", status ); for( k=0; k<2; k++ ) { /* The third test will FFT filter bolometers from time chunks in parallel */ msgOut( "", TASK_NAME ": Starting test 3 __parallel time: FFT filter__", status ); for( i=0; (i<(size_t)nthread) && (*status==SAI__OK); i++ ) { pdata = job_data + i; pdata->type = 2; /* FFT filter */ if( pdata->chunk1 >= nchunks ) { /* Nothing for this thread to do */ msgSeti( "W", i+1); msgOutif( MSG__DEBUG, "", "-- parallel time: skipping thread ^W, nothing to do", status); } else { /* Since we know there is one job_data per thread, just submit jobs immediately */ pdata->ijob = thrAddJob( wf, THR__REPORT_JOB, pdata, smfParallelTime, 0, NULL, status ); } } /* Wait until all of the submitted jobs have completed */ thrWait( wf, status ); /*** TIMER ***/ msgOutf( "", "** %f seconds to complete test", status, smf_timerupdate(&tv1,&tv2,status) ); msgOut( "", TASK_NAME ": Starting test 4 __FFTW filter using internal threading__", status ); for( i=0; (*status==SAI__OK)&&(i<nchunks); i++ ) { filt = smf_create_smfFilter( res[i]->sdata[0], status ); smf_filter_ident( filt, 1, status ); for( j=0; (*status==SAI__OK)&&(j<nsub); j++ ) { msgOutiff( MSG__DEBUG, "", " filter chunk %zu/%zu, bolo %zu/%zu", status, i+1, nchunks, j+1, nsub ); smf_filter_execute( wf, res[i]->sdata[j], filt, 0, 0, status ); } if( filt ) filt = smf_free_smfFilter( filt, status ); } /*** TIMER ***/ msgOutf( "", "** %f seconds to complete test", status, smf_timerupdate(&tv1,&tv2,status) ); } msgOut( "", TASK_NAME ": **************************************************************", status ); /* Series of short single-thread array index tests */ data = res[0]->sdata[0]; dat = data->pntr[0]; smf_get_dims( data, NULL, NULL, &nbolo, &ntslice, &ndata, &bstride, &tstride, status ); msgOut("","Array index test #1: two multiplies in inner loop",status); smf_timerinit( &tv1, &tv2, status ); for( i=0; i<nbolo; i++ ) { for( j=0; j<ntslice; j++ ) { dat[i*bstride + j*tstride] += 5; } } msgOutf( "", "** %f seconds to complete test", status, smf_timerupdate(&tv1,&tv2,status) ); msgOut("","Array index test #2: only index increments",status); smf_timerinit( &tv1, &tv2, status ); for( i=0; i<nbolo*bstride; i+=bstride ) { for( j=i; j<(i+ntslice*tstride); j+=tstride ) { dat[j] += 5; } } msgOutf( "", "** %f seconds to complete test", status, smf_timerupdate(&tv1,&tv2,status) ); msgOut("","Array index test #3: one multiply in outer loop",status); smf_timerinit( &tv1, &tv2, status ); offset = 0; for( i=0; i<nbolo; i++ ) { offset = i*bstride; for( j=0; j<ntslice; j++ ) { dat[offset] += 5; offset += tstride; } } msgOutf( "", "** %f seconds to complete test", status, smf_timerupdate(&tv1,&tv2,status) ); /* Clean up */ if( res ) { for( i=0; i<nchunks; i++ ) { if( res[i] ) { smf_close_related( &res[i], status ); } } res = astFree( res ); } job_data = astFree( job_data ); /* Ensure that FFTW doesn't have any used memory kicking around */ fftw_cleanup(); }
void smf_calc_stareimage( smfData *data, const int naver, int *status) { double *avdata = NULL; /* Pointer to averaged data */ int dims[2]; /* Dimensions of the stored image */ smfHead *hdr; /* Header information */ int j; /* Loop counter */ size_t npts; /* Number of points in the averaged data */ int numaver; /* Number of samples to average */ int numimages; /* Number of output STARE images */ int numsamples; /* Number of time slices (samples) */ int remainder; /* Remainder from dividing no of timeslices by number of frames to average */ HDSLoc *scu2redloc = NULL; /* Locator to SCU2RED extension */ double steptime; /* Step time per sample, sec */ double *zero = NULL; /* Bolometer zero points */ if ( *status != SAI__OK ) return; /* Check we have time-series data */ if ( data->ndims != 3) { *status = SAI__ERROR; errRep(FUNC_NAME, "File does not contain time series data - unable to process", status); return; } /* Check we have flatfielded data */ if ( !smf_history_check( data, "smf_flatfield", status) ) { if ( *status == SAI__OK ) { *status = SAI__ERROR; errRep(FUNC_NAME, "Data have not been flatfielded ", status); return; } } /* Do we have STARE data? */ hdr = data->hdr; if ( hdr->obsmode == SMF__OBS_STARE ) { msgOutif(MSG__VERB," ", "Processing STARE data", status); if (smf_history_check( data, "smf_calc_stareimage", status) ) { msgOut(" ", "File contains STARE data which has already been processed: proceeding but this WILL OVERWRITE any STARE images already written into the SCU2RED extension", status); } /* Number of output STARE images */ numsamples = (data->dims)[2]; /* If naver < 0 then re-calculate to give 1-second images */ if ( naver < 0 ) { smf_fits_getD(hdr, "STEPTIME", &steptime, status); numaver = 1.0 / steptime; } else if ( naver > numsamples ) { msgOutif(MSG__NORM, "", "Warning: NAVER exceeds the number of samples - will average entire time stream to create a single image", status); numaver = numsamples; } else { numaver = naver; } numimages = numsamples / numaver; /* Warn user if the number to average is not a factor of the number of time slices */ remainder = numsamples % numaver; if ( remainder != 0 ) { msgSeti("R", remainder); msgSeti("N", numaver); msgSeti("T", numsamples); msgOutif(MSG__NORM, "", "Warning: NAVER (^N) is not a factor of the number of time slices (^T): final ^R samples will not be included in an image", status); } /* Helpful info for the user */ msgSeti("N",numimages); if ( numimages == 1 ) { msgSetc("IM","image"); } else { msgSetc("IM","images"); } msgOutif( MSG__VERB, "", "Calculating ^N STARE ^IM", status ); /* Obtain a locator for the extension where for the images will be stored */ scu2redloc = smf_get_xloc(data, "SCU2RED", "SCUBA2_MAP_ARR", "WRITE", 0, NULL, status); /* Set the dimensions of the output images - they are all the same so they can be safely set outside the loop below */ dims[0] = (data->dims)[0]; dims[1] = (data->dims)[1]; /* Loop over the number of output images */ for ( j=0; j<numimages; j++) { /* Average the time stream data over the desired interval */ smf_average_dataD( data, j*numaver, numaver, 1, &avdata, &npts, status ); /* Store the averaged data as an image */ smf_store_image( data, scu2redloc, j, 2, dims, numaver, 0, 0, avdata, NULL, status); avdata = astFree( avdata ); zero = astFree( zero ); } /* Add a history entry if everything's OK */ smf_history_add(data, "smf_calc_stareimage", status ); /* Release SCU2RED locator */ datAnnul( &scu2redloc, status ); } else { msgOutif(MSG__NORM," ", "Input file is not a STARE observation - ignoring", status); } }
void smf_addpolanal( AstFrameSet *fset, smfHead *hdr, AstKeyMap *config, int *status ){ /* Local Variables */ AstCmpMap *tmap; AstFrame *cfrm; AstFrame *pfrm; AstFrame *tfrm; AstFrameSet *tfs; AstPermMap *pm; char *polnorth = NULL; const char *cursys; const char *trsys; int aloff; int icurr; int inperm[2]; int outperm[2]; int pol2fp; /* Check inherited status, and also check the supplied angle is not bad. */ if( *status != SAI__OK ) return; /* Begin an AST object context. */ astBegin; /* Get the value of the POLNORTH FITS keyword from the supplied header. The rest only happens if the keyword is found. */ if( astGetFitsS( hdr->fitshdr, "POLNORTH", &polnorth ) ) { /* Normally, we do not allow maps to be made from Q/U time streams that use focal plane Y as the reference direction (because of the problems of sky rotation). Therefore we report an error. However, we do need to make such maps as part of the process of determining the parameters of the Instrumental Polarisation (IP) model. So only report the error if "pol2fp" config parameter is non-zero. */ if( !strcmp( polnorth, "FPLANE" ) ) { astMapGet0I( config, "POL2FP", &pol2fp ); if( pol2fp ) { msgBlank( status ); msgOut( "", "WARNING: The input NDFs hold POL-2 Q/U data specified " "with respect to focal plane Y.",status ); msgOut( "", "Maps should normally be made from POL-2 data specified " "with respect to celestial north.",status ); msgOut( "", "The output map will not contain a POLANAL Frame and " "so will be unusable by POLPACK applications.",status ); msgBlank( status ); } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "The input NDFs hold POL-2 Q/U data specified with " "respect to focal plane Y.",status ); errRep( "", "Maps can only be made from POL-2 data specified with " "respect to celestial north.",status ); } /* If the ref. direction is celestial north, create a suitable Frame and Mapping and add them into the supplied FrameSet. */ } else { /* Check the current Frame is a SkyFrame. */ cfrm = astGetFrame( fset, AST__CURRENT ); if( astIsASkyFrame( cfrm ) ) { /* Create a POLANAL Frame. */ pfrm = astFrame( 2, "Domain=POLANAL" ); astSet( pfrm, "Title=Polarimetry reference frame" ); astSet( pfrm, "Label(1)=Polarimetry reference direction" ); astSet( pfrm, "Label(2)=" ); /* Create a PermMap that ensures that axis 1 of the POLANAL Frame is parallel to the latitude axis (i.e. north) of the curent Frame (the current Frame axes may have been swapped). */ outperm[ 0 ] = astGetI( cfrm, "LatAxis" ); outperm[ 1 ] = astGetI( cfrm, "LonAxis" ); inperm[ outperm[ 0 ] - 1 ] = 1; inperm[ outperm[ 1 ] - 1 ] = 2; pm = astPermMap( 2, inperm, 2, outperm, NULL, " " ); /* Record the index of the original current Frame. */ icurr = astGetI( fset, "Current" ); /* Determine the system to use. */ if( !strcmp( polnorth, "TRACKING" ) ) { trsys = sc2ast_convert_system( hdr->state->tcs_tr_sys, status ); } else { trsys = polnorth; } /* If the current Frame in the supplied FrameSet has this system. Then we use the above PermMap to connect the POLANAL Frame directly to the current Frame. */ cursys = astGetC( cfrm, "System" ); if( trsys && cursys && !strcmp( cursys, trsys ) ) { astAddFrame( fset, AST__CURRENT, pm, pfrm ); /* Otherwise we need to get a Mapping from the current Frame to the required frame. */ } else { /* Take a copy of the current Frame (in order to pick up epoch, observatory position, etc), and set its System to the required system. */ tfrm = astCopy( cfrm ); astSetC( tfrm, "System", trsys ); /* Get the Mapping from the original current Frame to this modified copy. Ensure alignment happens in absolute coords (alignment in offset coords is always a unit mapping and so no rotation occurs). */ aloff = astGetI( cfrm, "AlignOffset" ); if( aloff ) { astSetI( cfrm, "AlignOffset", 0 ); astSetI( tfrm, "AlignOffset", 0 ); } tfs = astConvert( cfrm, tfrm, "SKY" ); if( aloff ) { astSetI( cfrm, "AlignOffset", 1 ); astSetI( tfrm, "AlignOffset", 1 ); } if( tfs ) { /* Use it, in series with with the above PermMap, to connect the POLANAL frame to the current Frame. */ tmap = astCmpMap( astGetMapping( tfs, AST__BASE, AST__CURRENT ), pm, 1, " " ); astAddFrame( fset, AST__CURRENT, astSimplify( tmap ), pfrm ); /* Report an error if the mapping from current to required system could not be found. */ } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRepf( "", "smf_addpolanal: Could not convert Frame " "from %s to %s (prgramming error).", status, cursys, trsys ); } } /* Re-instate the original current Frame. */ astSetI( fset, "Current", icurr ); /* Report an error if the current Frame is not a SkyFrame. */ } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "smf_addpolanal: The current Frame in the " "supplied FrameSet is not a SkyFrame (prgramming " "error).", status ); } } } /* End the AST object context. */ astEnd; }
void smf_grp_related( const Grp *igrp, const size_t grpsize, const int grouping, const int checksubinst, double maxlen_s, double *srate_maxlen, AstKeyMap *keymap, dim_t *maxconcatlen, dim_t *maxfilelen, smfGroup **group, Grp **basegrp, dim_t *pad, int *status ) { /* Local variables */ size_t *chunk=NULL; /* Array of flags for continuous chunks */ dim_t * chunklen = NULL; /* Length of continuous chunk */ size_t currentindex = 0; /* Counter */ char cwave[10]; /* String containing wavelength */ smfData *data = NULL; /* Current smfData */ double downsampscale=0; /* Angular scale downsampling size */ double downsampfreq=0; /* Target downsampling frequency */ AstKeyMap * grouped = NULL; /* Primary AstKeyMap for grouping */ size_t i; /* Loop counter for index into Grp */ int isFFT=0; /* Set if data are 4d FFT */ size_t j; /* Loop counter */ int *keepchunk=NULL; /* Flag for chunks that will be kept */ dim_t maxconcat=0; /* Longest continuous chunk length */ dim_t maxflen=0; /* Max file length in time steps */ dim_t maxlen=0; /* Maximum concat length in samples */ int maxlen_scaled=0; /* Set once maxlen has been scaled, if needed */ dim_t maxpad=0; /* Maximum padding neeed for any input file */ size_t maxrelated = 0; /* Keep track of max number of related items */ size_t *new_chunk=NULL; /* keeper chunks associated with subgroups */ dim_t *new_tlen=NULL; /* tlens for new_subgroup */ size_t ngroups = 0; /* Counter for subgroups to be stored */ size_t nkeep = 0; /* Number of chunks to keep */ dim_t * piecelen = NULL; /* Length of single file */ smf_subinst_t refsubinst; /* Subinst of first file */ size_t **subgroups = NULL; /* Array containing index arrays to parent Grp */ smf_subinst_t subinst; /* Subinst of current file */ if ( *status != SAI__OK ) return; if( maxlen_s < 0 ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": maxlen_s cannot be < 0!", status ); return; } /* Get downsampling parameters */ if( keymap ) { smf_get_cleanpar( keymap, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &downsampscale, &downsampfreq, NULL, NULL, NULL, NULL, status ); if( downsampscale && downsampfreq ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": both downsampscale and downsampfreq are set", status ); return; } } /* Initialize refcwave */ refsubinst = SMF__SUBINST_NONE; /* Loop over files in input Grp: remember Grps are indexed from 1 */ grouped = astKeyMap( "SortBy=KeyUp" ); for (i=1; i<=grpsize; i++) { char newkey[128]; char dateobs[81]; char subarray[10]; size_t nrelated = 0; AstKeyMap * filemap = NULL; AstKeyMap * indexmap = NULL; /* First step: open file and harvest metadata */ smf_open_file( NULL, igrp, i, "READ", SMF__NOCREATE_DATA, &data, status ); if (*status != SAI__OK) break; if( i==1 ) { isFFT = smf_isfft( data, NULL, NULL, NULL, NULL, NULL, status ); } else if( smf_isfft(data, NULL, NULL, NULL, NULL, NULL, status) != isFFT ){ *status = SAI__ERROR; errRep( "", FUNC_NAME ": mixture of time-series and FFT data encountered!", status ); break; } /* If maxlen has not been set, do it here */ if( !maxlen && maxlen_s && data->hdr->steptime) { maxlen = (dim_t) (maxlen_s / data->hdr->steptime ); } /* Return srate_maxlen if requested: may want to know this number even if maxlen_s is not set. Only calculate once, although it gets overwritten once later if down-sampling. */ if( (i==1) && srate_maxlen && data->hdr->steptime ) { *srate_maxlen = 1. / (double) data->hdr->steptime; } /* If requested check to see if we are mixing wavelengths */ if( checksubinst ) { if( refsubinst == SMF__SUBINST_NONE ) { refsubinst = smf_calc_subinst( data->hdr, status ); } subinst = smf_calc_subinst( data->hdr, status ); if( subinst != refsubinst ) { const char *refsubstr = smf_subinst_str( refsubinst, status ); const char *substr = smf_subinst_str( subinst, status ); *status = SAI__ERROR; smf_smfFile_msg( data->file, "FILE", 1, "<unknown>" ); msgSetc( "REFSUB", refsubstr ); msgSetc( "SUB", substr ); errRep( "", FUNC_NAME ": ^FILE uses sub-instrument ^SUB which doesn't match " "reference ^REFSUB", status ); } } /* Want to form a key that will be unique for a particular subscan We know that DATE-OBS will be set for SCUBA-2 files and be the same for a single set. Prefix by wavelength if we are grouping by wavelength. */ newkey[0] = '\0'; smf_find_subarray( data->hdr, subarray, sizeof(subarray), NULL, status ); if( grouping == 1 ) { /* Group different wavelengths separately */ smf_fits_getS( data->hdr, "WAVELEN", cwave, sizeof(cwave), status); one_strlcat( newkey, cwave, sizeof(newkey), status ); one_strlcat( newkey, "_", sizeof(newkey), status ); } if( grouping == 2 ) { /* Group different subarrays separately */ one_strlcat( newkey, subarray, sizeof(newkey), status ); } smf_fits_getS( data->hdr, "DATE-OBS", dateobs, sizeof(dateobs), status ); one_strlcat( newkey, dateobs, sizeof(newkey), status ); /* Include the dimentionality of the time series in the primary key so that we do not end up doing something confusing like relating a truncated file with a full length file */ if (*status == SAI__OK) { dim_t dims[3]; char formatted[32]; smf_get_dims( data, &dims[0], &dims[1], NULL, &dims[2], NULL, NULL, NULL, status ); sprintf(formatted, "_%" DIM_T_FMT "_%" DIM_T_FMT "_%" DIM_T_FMT, dims[0], dims[1], dims[2]); one_strlcat( newkey, formatted, sizeof(newkey), status ); } /* May want to read the dimensionality of the file outside of loop so that we can compare values when storing in the keymap */ /* Now we want to create a keymap based on this key */ if (!astMapGet0A( grouped, newkey, &filemap ) ) { int itemp = 0; double steptime = data->hdr->steptime; dim_t ntslice = 0; dim_t thispad; /* Padding neeed for current input file */ filemap = astKeyMap( " " ); astMapPut0A( grouped, newkey, filemap, NULL ); /* Fill up filemap with general information on this file */ smf_find_seqcount( data->hdr, &itemp, status ); astMapPut0I( filemap, "SEQCOUNT", itemp, NULL ); smf_fits_getI( data->hdr, "NSUBSCAN", &itemp, status ); astMapPut0I( filemap, "NSUBSCAN", itemp, NULL ); /* Number of time slices */ smf_get_dims( data, NULL, NULL, NULL, &ntslice, NULL, NULL, NULL, status ); /* Find length of down-sampled data, new steptime and maxlen */ if( (downsampscale || downsampfreq) && data->hdr && (*status==SAI__OK) ) { double scalelen; if( downsampscale ) { if( data->hdr->scanvel != VAL__BADD ) { double oldscale = steptime * data->hdr->scanvel; scalelen = oldscale / downsampscale; } else if( *status == SAI__OK ) { *status = SAI__ERROR; scalelen = VAL__BADD; smf_smfFile_msg( data->file, "FILE", 1, "" ); errRep( "", FUNC_NAME ": can't resample ^FILE because it has " "unknown scan velocity", status ); } } else { if( steptime ) { double oldsampfreq = 1./steptime; scalelen = downsampfreq / oldsampfreq; } else { *status = SAI__ERROR; scalelen = VAL__BADD; smf_smfFile_msg( data->file, "FILE", 1, "" ); errRep( "", FUNC_NAME ": can't resample ^FILE because it has " "unknown sample rate", status ); } } /* only down-sample if it will be a reasonable factor */ if( (*status==SAI__OK) && (scalelen <= SMF__DOWNSAMPLIMIT) ) { smf_smfFile_msg(data->file, "FILE", 1, "" ); msgOutiff( MSG__VERB, "", FUNC_NAME ": will down-sample file ^FILE from %5.1lf Hz to " "%5.1lf Hz", status, (1./steptime), (scalelen/steptime) ); ntslice = round(ntslice * scalelen); /* If maxlen has been requested, and we have not already worked out a scaled version (just uses the sample rates for the first file... should be close enough -- the alternative is a 2-pass system). */ if( !maxlen_scaled ) { maxlen = round(maxlen*scalelen); maxlen_scaled = 1; msgOutiff( MSG__VERB, "", FUNC_NAME ": requested maxlen %g seconds = %" DIM_T_FMT " down-sampled " "time-slices", status, maxlen_s, maxlen ); /* Return updated srate_maxlen for down-sampling if requested */ if( srate_maxlen ) { *srate_maxlen = scalelen/steptime; } } } } /* Check that an individual file is too long (we assume related files are all the same) */ if( maxlen && (ntslice > maxlen) && *status == SAI__OK) { *status = SAI__ERROR; msgSeti("NTSLICE",ntslice); msgSeti("MAXLEN",maxlen); smf_smfFile_msg( data->file, "FILE", 1, "" ); errRep(FUNC_NAME, "Number of time steps in file ^FILE time exceeds maximum " "(^NTSLICE>^MAXLEN)", status); } /* Scaled values of ntslice and maximum length */ astMapPut0I( filemap, "NTSLICE", ntslice, NULL ); /* Work out the padding needed for this file including downsampling. */ if( keymap ) { thispad = smf_get_padding( keymap, 0, data->hdr, VAL__BADD, status ); if( thispad > maxpad ) maxpad = thispad; } else { thispad = 0; } astMapPut0I( filemap, "PADDING", thispad, NULL ); /* Update maxflen */ if( ntslice > maxflen ) { maxflen = ntslice; } /* Store OBSID or OBSIDSS depending on whether we are grouping by wavelength */ if (grouping) { astMapPut0C( filemap, "OBSID", data->hdr->obsidss, NULL ); } else { char obsid[81]; smf_getobsidss( data->hdr->fitshdr, obsid, sizeof(obsid), NULL, 0, status ); astMapPut0C( filemap, "OBSID", obsid, NULL ); } } /* Store the file index in another keymap indexed by subarray */ if ( !astMapGet0A( filemap, "GRPINDICES", &indexmap ) ) { indexmap = astKeyMap( "SortBy=KeyUp" ); astMapPut0A( filemap, "GRPINDICES", indexmap, NULL ); } astMapPut0I( indexmap, subarray, i, NULL ); /* Need to track the largest number of related subarrays in a single slot */ nrelated = astMapSize( indexmap ); if (nrelated > maxrelated) maxrelated = nrelated; /* Free resources */ filemap = astAnnul( filemap ); indexmap = astAnnul( indexmap ); smf_close_file( NULL, &data, status ); } /* We now know how many groups there are */ ngroups = astMapSize( grouped ); /* Sort out chunking. The items are sorted by date and then by wavelength. We define a continuous chunk if it has the same OBSID, the same SEQCOUNT and NSUBSCAN increments by one from the previous entry. Also count number of related items in each slot. */ if (*status == SAI__OK) { typedef struct { /* somewhere to store the values easily */ char obsid[81]; char related[81]; /* for concatenated subarrays */ int nsubscan; int seqcount; } smfCompareSeq; smfCompareSeq current; smfCompareSeq previous; dim_t totlen = 0; size_t thischunk; /* Get the chunk flags and also store the size of the chunk */ chunk = astCalloc( ngroups, sizeof(*chunk) ); chunklen = astCalloc( ngroups, sizeof(*chunklen) ); piecelen = astCalloc( ngroups, sizeof(*piecelen) ); thischunk = 0; /* The current chunk */ for (i=0; i<ngroups; i++) { AstKeyMap * thismap = NULL; AstKeyMap * grpindices = NULL; const char * tempstr = NULL; int thistlen = 0; size_t nsubarrays = 0; /* Get the keymap entry for this slot */ astMapGet0A( grouped, astMapKey(grouped, i), &thismap ); /* Get info for length limits */ astMapGet0I( thismap, "NTSLICE", &thistlen ); piecelen[i] = thistlen; if (isFFT) { /* Never concatenate FFT data */ thismap = astAnnul(thismap); chunk[i] = i; chunklen[i] = thistlen; continue; } /* Get indices information and retrieve the sub-instrument names in sort order to concatenate for comparison. We only store in a continuous chunk if we have the same subarrays for the whole chunk. */ astMapGet0A( thismap, "GRPINDICES", &grpindices ); nsubarrays = astMapSize( grpindices ); (current.related)[0] = '\0'; for (j = 0; j < nsubarrays; j++ ) { one_strlcat( current.related, astMapKey(grpindices, j), sizeof(current.related), status ); } grpindices = astAnnul( grpindices ); /* Fill in the current struct */ astMapGet0I( thismap, "SEQCOUNT", &(current.seqcount) ); astMapGet0I( thismap, "NSUBSCAN", &(current.nsubscan) ); astMapGet0C( thismap, "OBSID", &tempstr ); one_strlcpy( current.obsid, tempstr, sizeof(current.obsid), status ); /* First chunk is special, else compare */ if (i == 0) { totlen = thistlen; } else { if ( ( current.seqcount == previous.seqcount ) && ( current.nsubscan - previous.nsubscan == 1 ) && ( strcmp( current.obsid, previous.obsid ) == 0 ) && ( strcmp( current.related, previous.related ) == 0 ) ) { /* continuous - check length */ totlen += thistlen; if ( maxlen && totlen > maxlen ) { thischunk++; totlen = thistlen; /* reset length */ } else { /* Continuous */ } } else { /* discontinuity */ thischunk++; totlen = thistlen; /* Update length of current chunk */ } } chunklen[thischunk] = totlen; chunk[i] = thischunk; memcpy( &previous, ¤t, sizeof(current) ); thismap = astAnnul( thismap ); } } /* Decide if we are keeping a chunk by looking at the length. */ maxconcat = 0; nkeep = 0; keepchunk = astMalloc( ngroups*sizeof(*keepchunk) ); for (i=0; i<ngroups; i++) { size_t thischunk; thischunk = chunk[i]; if ( chunklen[thischunk] < SMF__MINCHUNKSAMP ) { /* Warning message */ msgSeti("LEN",chunklen[thischunk]); msgSeti("MIN",SMF__MINCHUNKSAMP); msgOut( " ", "SMF_GRP_RELATED: ignoring short chunk (^LEN<^MIN)", status); keepchunk[i] = 0; } else { keepchunk[i] = 1; if (maxconcat < chunklen[thischunk]) maxconcat = chunklen[thischunk]; nkeep++; } } /* If no useful chunks generate an error */ if( (*status==SAI__OK) && (!nkeep) ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": No useful chunks.", status ); goto CLEANUP; } /* Allocate a subgroup array of the right size and fill it. They keymap is sorted by date (and wavelength) so we can always index into it by using indices from the subgroup. */ subgroups = astCalloc( nkeep, sizeof(*subgroups) ); new_chunk = astCalloc( nkeep, sizeof(*new_chunk) ); new_tlen = astCalloc( nkeep, sizeof(*new_tlen) ); currentindex = 0; for (i=0;i<ngroups;i++) { AstKeyMap * thismap = NULL; AstKeyMap * grpindices = NULL; size_t nsubarrays = 0; size_t *indices = astCalloc( maxrelated, sizeof(*indices) ); /* skip if we are dropping this chunk */ if (!keepchunk[i]) continue; /* Get the keymap entry for this slot */ astMapGet0A( grouped, astMapKey(grouped, i), &thismap ); /* Get the indices keymap */ astMapGet0A( thismap, "GRPINDICES", &grpindices ); nsubarrays = astMapSize( grpindices ); for (j=0; j<nsubarrays; j++) { int myindex; astMapGet0I( grpindices, astMapKey(grpindices, j), &myindex ); indices[j] = myindex; } grpindices = astAnnul( grpindices ); thismap = astAnnul( thismap ); subgroups[currentindex] = indices; new_chunk[currentindex] = chunk[i]; new_tlen[currentindex] = piecelen[i]; currentindex++; } /* Create the smfGroup */ *group = smf_construct_smfGroup( igrp, subgroups, new_chunk, new_tlen, nkeep, maxrelated, 0, status ); /* Return maxfilelen if requested */ if( maxfilelen ) { *maxfilelen = maxflen; } /* Return maxconcatlen if requested */ if( maxconcatlen ) { *maxconcatlen = maxconcat; } /* Create a base group for output files if required */ /* Create a base group of filenames */ if (*status == SAI__OK && basegrp ) { *basegrp = smf_grp_new( (*group)->grp, "Base Group", status ); /* Loop over time chunks */ for( i=0; (*status==SAI__OK)&&(i<(*group)->ngroups); i++ ) { size_t idx; /* Check for new continuous chunk */ if( i==0 || ( (*group)->chunk[i] != (*group)->chunk[i-1]) ) { /* Loop over subarray */ for( idx=0; idx<(*group)->nrelated; idx++ ) { size_t grpindex = (*group)->subgroups[i][idx]; if ( grpindex > 0 ) { ndgCpsup( (*group)->grp, grpindex, *basegrp, status ); } } } } } CLEANUP: keepchunk = astFree( keepchunk ); chunk = astFree( chunk ); chunklen = astFree( chunklen ); piecelen = astFree( piecelen ); grouped = astAnnul( grouped ); if( *status != SAI__OK ) { /* free the group */ if (basegrp && *basegrp) grpDelet( basegrp, status ); if (group && *group) { smf_close_smfGroup( group, status ); } else { /* have to clean up manually */ new_chunk = astFree( new_chunk ); new_tlen = astFree( new_tlen ); if( subgroups ) { size_t isub; for( isub=0; isub<nkeep; isub++ ) { subgroups[isub] = astFree( subgroups[isub] ); } subgroups = astFree( subgroups ); } } } /* Return the maximum padding if required. */ if( pad ) *pad = maxpad; }
int smf_initial_sky( ThrWorkForce *wf, AstKeyMap *keymap, smfDIMMData *dat, int *iters, int *status ) { /* Local Variables: */ char refparam[ DAT__SZNAM ];/* Name for reference NDF parameter */ const char *cval; /* The IMPORTSKY string value */ double *ptr; /* Pointer to NDF Data array */ double *vptr; /* Pointer to NDF Variance array */ int indf1; /* Id. for supplied reference NDF */ int indf2; /* Id. for used section of reference NDF */ int nel; /* Number of mapped NDF pixels */ int result; /* Returned flag */ int there; /* Is there a smurf extension in the NDF? */ int update; /* Was NDF opened for UPDATE access? */ size_t i; /* Loop count */ size_t junk; /* Unused value */ /* Initialise the returned value to indicate no sky has been subtractred. */ result = 0; /* Assume the sky map was not created by an interupted previous run of makemap. */ *iters = -1; /* Check inherited status. */ if( *status != SAI__OK ) return result; /* Begin an AST context. */ astBegin; /* The IMPORTSKY config parameter should have the name of the ADAM parameter to use for acquiring the NDF that contains the initial sky estimate. If IMPORTSKY is "1", use REF. */ cval = NULL; astMapGet0C( keymap, "IMPORTSKY", &cval ); if( cval ) { if( !astChrMatch( cval, "REF" ) && !astChrMatch( cval, "MASK2" ) && !astChrMatch( cval, "MASK3" ) ) { astMapGet0I( keymap, "IMPORTSKY", &result ); cval = ( result > 0 ) ? "REF" : NULL; } if( cval ) { result = 1; strcpy( refparam, cval ); astChrCase( NULL, refparam, 1, 0 ); } } /* Do nothing more if we are not subtracting an initial sky from the data. */ if( result && *status == SAI__OK ) { /* Begin an NDF context. */ ndfBegin(); /* Get an identifier for the NDF using the associated ADAM parameter. First try UPDATE access. If this fails try READ access. */ ndfAssoc( refparam, "UPDATE", &indf1, status ); if( *status != SAI__OK ) { errAnnul( status ); ndfAssoc( refparam, "READ", &indf1, status ); update = 0; } else { update = 1; } /* Tell the user what we are doing. */ ndfMsg( "N", indf1 ); msgOut( "", "Using ^N as the initial guess at the sky", status ); /* Get a section from this NDF that matches the bounds of the map. */ ndfSect( indf1, 2, dat->lbnd_out, dat->ubnd_out, &indf2, status ); /* Ensure masked values are not set bad in the mapped data array. */ ndfSbb( 0, indf2, status ); /* Map the data array section, and copy it into the map buffer. */ ndfMap( indf2, "DATA", "_DOUBLE", "READ", (void **) &ptr, &nel, status ); if( *status == SAI__OK ) { memcpy( dat->map, ptr, dat->msize*sizeof(*ptr)); } /* Map the variance array section, and copy it into the map buffer. */ ndfState( indf2, "VARIANCE", &there, status ); if( there ) { ndfMap( indf2, "VARIANCE", "_DOUBLE", "READ", (void **) &vptr, &nel, status ); if( *status == SAI__OK ) { memcpy( dat->mapvar, vptr, dat->msize*sizeof(*vptr)); } } /* If the NDF was created by a previous run of makemap that was interupted using control-C, it will contain a NUMITER item in the smurf extension, which gives the number of iterations that were completed before the map was created. Obtain and return this value, if it exists. */ ndfXstat( indf1, SMURF__EXTNAME, &there, status ); if( there ) ndfXgt0i( indf1, SMURF__EXTNAME, "NUMITER", iters, status ); /* If the NDF has a Quality component, import it and create initial AST, FLT, PCA, SSN and COM masks from it. These will often be over-ridden by new masks calculated with smf_calcmodel_ast below, but will not be over-written if the masks have been frozen by xxx.zero_freeze. */ ndfState( indf2, "Quality", &there, status ); if( there && dat->mapqual ) { smf_qual_t *qarray = smf_qual_map( wf, indf2, "Read", NULL, &junk, status ); if( *status == SAI__OK ) { smf_qual_t *pq = qarray; for( i = 0; i < dat->msize; i++,pq++ ) { if( *pq & SMF__MAPQ_AST ) { if( !dat->ast_mask ) dat->ast_mask = astCalloc( dat->msize, sizeof( *(dat->ast_mask) ) ); (dat->ast_mask)[ i ] = 1; } if( *pq & SMF__MAPQ_FLT ) { if( !dat->flt_mask ) dat->flt_mask = astCalloc( dat->msize, sizeof( *(dat->flt_mask) ) ); (dat->flt_mask)[ i ] = 1; } if( *pq & SMF__MAPQ_COM ) { if( !dat->com_mask ) dat->com_mask = astCalloc( dat->msize, sizeof( *(dat->com_mask) ) ); (dat->com_mask)[ i ] = 1; } if( *pq & SMF__MAPQ_SSN ) { if( !dat->ssn_mask ) dat->ssn_mask = astCalloc( dat->msize, sizeof( *(dat->ssn_mask) ) ); (dat->ssn_mask)[ i ] = 1; } if( *pq & SMF__MAPQ_PCA ) { if( !dat->pca_mask ) dat->pca_mask = astCalloc( dat->msize, sizeof( *(dat->pca_mask) ) ); (dat->pca_mask)[ i ] = 1; } } } qarray = astFree( qarray ); } /* Indicate the map arrays within the supplied smfDIMMData structure now contain usable values. We need to do this before calling smf_calcmodel_ast below so that the right mask gets used in smf_calcmodel_ast. */ dat->mapok = 1; /* Apply any existinction correction to the cleaned bolometer data. */ if( dat->ext ) smf_calcmodel_ext( wf, dat, 0, keymap, dat->ext, 0, status); /* Sample the above map at the position of each bolometer sample and subtract the sampled value from the cleaned bolometer value. */ smf_calcmodel_ast( wf, dat, 0, keymap, NULL, SMF__DIMM_PREITER, status); /* Remove any existinction correction to the modifed bolometer data. */ if( dat->ext ) smf_calcmodel_ext( wf, dat, 0, keymap, dat->ext, SMF__DIMM_INVERT, status); /* If the NDF was opened with UPDATE access, update the quality array in the NDF to reflect the AST mask created by smf_calcmodel_ast above. */ if( update ) { smf_qual_t *qarray = astStore( NULL, dat->mapqual, dat->msize*sizeof(*qarray) ); qarray = smf_qual_unmap( wf, indf2, SMF__QFAM_MAP, qarray, status ); } /* End the NDF context. */ ndfEnd( status ); } /* End the AST context. */ astEnd; /* Return the pointer to the boolean mask. */ return result; }
void smf_rebincube_ast( ThrWorkForce *wf, smfData *data, int first, int last, int *ptime, dim_t nchan, dim_t ndet, dim_t nslice, dim_t nel, dim_t nxy, dim_t nout, dim_t dim[3], AstMapping *ssmap, AstSkyFrame *abskyfrm, AstMapping *oskymap, Grp *detgrp, int moving, int usewgt, int spread, const double params[], int genvar, double tfac, double fcon, float *data_array, float *var_array, double *wgt_array, float *texp_array, float *teff_array, int *good_tsys, int64_t *nused, int *status ){ /* Local Variables */ AstCmpMap *detmap = NULL; /* Mapping from 1D det. index to 2D i/p "grid" coords */ AstMapping *dtotmap = NULL; /* 1D det index->o/p GRID Mapping */ AstMapping *fullmap = NULL; /* WCS->GRID LutMap from input WCS FrameSet */ AstMapping *lutmap = NULL; /* Mapping that identifies detectors to be used */ AstMapping *splut = NULL; /* Spatial LutMap */ AstMapping *sslut = NULL; /* Spectral LutMap */ AstMapping *totmap = NULL; /* WCS->GRID Mapping from input WCS FrameSet */ AstPermMap *pmap; /* Mapping to rearrange output axes */ const char *name = NULL; /* Pointer to current detector name */ const double *tsys = NULL; /* Pointer to Tsys value for first detector */ dim_t iv; /* Vector index into output 3D array */ double *detlut = NULL; /* Work space for detector mask */ double blk_bot[ 2*MAXTHREADS + 1 ]; /* First o/p channel no. in each block */ double con; /* Constant value */ double dtemp; /* Temporary value */ double tcon; /* Variance factor for whole time slice */ float *detwork = NULL; /* Work array for detector values */ float *tdata = NULL; /* Pointer to start of input time slice data */ float *varwork = NULL; /* Work array holding variances for 1 slice/channel */ float *vp = NULL; /* Pointer to next "varwork" element */ float invar; /* Input variance */ float rtsys; /* Tsys value */ float teff; /* Effective integration time */ float texp; /* Total time ( = ton + toff ) */ int *nexttime; /* Pointer to next time slice index to use */ int ast_flags; /* Basic flags to use with astRebinSeq */ int blk_size; /* Number of channels processed by a single thread */ int found; /* Was current detector name found in detgrp? */ int iblock; /* Index of current spectral block */ dim_t ichan; /* Index of current channel */ dim_t idet; /* detector index */ int ignore; /* Ignore this time slice? */ int inperm[ 3 ]; /* Input axis permutation array */ dim_t itime; /* Index of current time slice */ int64_t junk; /* Unused parameter */ int lbnd_in[ 2 ]; /* Lower input bounds on receptor axis */ int ldim[ 3 ]; /* Output array lower GRID bounds */ int maxthreads; /* Max no. of threads to use when re-binning */ int nblock; /* Number of spectral blocks */ int nthreads; /* Number of threads to use when re-binning */ int outperm[ 3 ]; /* Output axis permutation array */ int timeslice_size; /* Number of elements in a time slice */ int ubnd_in[ 2 ]; /* Upper input bounds on receptor axis */ int uddim[ 1 ]; /* Detector array upper GRID bounds */ int udim[ 3 ]; /* Output array upper GRID bounds */ smfHead *hdr = NULL; /* Pointer to data header for this time slice */ /* Check the inherited status. */ if( *status != SAI__OK ) return; /* Store a pointer to the input NDFs smfHead structure. */ hdr = data->hdr; /* Fill an array with the lower grid index bounds of the output. */ ldim[ 0 ] = 1; ldim[ 1 ] = 1; ldim[ 2 ] = 1; /* Integer upper grid index bounds of the output. */ udim[ 0 ] = dim[ 0 ]; udim[ 1 ] = dim[ 1 ]; udim[ 2 ] = dim[ 2 ]; /* Integer upper bounds of detector array. */ uddim[ 0 ] = ndet; /* Store the size of an input time slice. */ timeslice_size = nel/nslice; /* Create a LutMap that holds the output spectral axis GRID value at the centre of each input spectral axis pixel. LutMaps are faster to evaluate, and so astRebinSeq will go faster. We can use LutMaps without loosing accuracy since astRebinSeq only ever transforms the GRID values at input pixel centres (i.e. integer GRID values), and so the LutMap will always return a tabulated value rather than an interpolated value. */ atlTolut( (AstMapping *) ssmap, 1.0, (double) nchan, 1.0, "LutInterp=1", &sslut, status ); /* If this is the first pass through this file, initialise the arrays. */ if( first ) smf_rebincube_init( 0, nxy, nout, genvar, data_array, var_array, wgt_array, texp_array, teff_array, &junk, status ); /* Initialisation the flags for astRebinSeq (we do not include flag AST__REBININIT because the arrays have been initialised). */ ast_flags = AST__USEBAD; if( usewgt ) ast_flags = ast_flags | AST__VARWGT; if( genvar == 1 ) { ast_flags = ast_flags | AST__GENVAR; } else if( genvar == 2 ) { ast_flags = ast_flags | AST__USEVAR; } /* If required, allocate a work array to hold all the input variances for a single time slice. */ if( usewgt || genvar == 2 ) varwork = astMalloc( timeslice_size * sizeof( float ) ); /* Allocate a work array to hold the exposure time for each detector. */ detwork = astMalloc( ndet * sizeof( float ) ); /* Debug message */ if( data->file ) { msgOutiff( MSG__DEBUG, " ", "smf_rebincube_ast: Using %zu detectors " "from data file '%s'.", status, ndet, data->file->name ); } /* If we are dealing with more than 1 detector, create a LutMap that holds the input GRID index of every detector to be included in the output, and AST__BAD for every detector that is not to be included in the output cube. First allocate the work space for the LUT. */ if( ndet > 1 ) { detlut = astMalloc( ndet*sizeof( double ) ); /* Initialise a string to point to the name of the first detector for which data is available */ name = hdr->detname; /* Loop round all detectors for which data is available. */ for( idet = 0; idet < ndet; idet++ ) { /* Store the input GRID coord of this detector. GRID coords start at 1, not 0. */ detlut[ idet ] = idet + 1.0; /* If a group of detectors to be used was supplied, search the group for the name of the current detector. If not found, set the GRID coord bad. This will cause astRebinSeq to ignore data from the detector. */ if( detgrp ) { found = grpIndex( name, detgrp, 1, status ); if( !found ) detlut[ idet ] = AST__BAD; } /* Move on to the next available detector name. */ name += strlen( name ) + 1; } /* Create the LutMap. */ lutmap = (AstMapping *) astLutMap( ndet, detlut, 1.0, 1.0, "LutInterp=1" ); /* If we only have 1 detector, use a UnitMap instead of a LutMap (lutMaps must have 2 or more table entries). */ } else { lutmap = (AstMapping *) astUnitMap( 1, " " ); } /* Combine the above LutMap with a 1-input, 2-output PermMap that copies its input to create its first output, and assigns a constant value of 1.0 to its second output. We need to do this because smf_tslice returns a 2D GRID system (even though the second GRID axis is not actually used). */ inperm[ 0 ] = 1; outperm[ 0 ] = 1; outperm[ 1 ] = -1; con = 1.0; detmap = astCmpMap( lutmap, astPermMap( 1, inperm, 2, outperm, &con, " " ), 1, " " ); /* Store the bounds of a single time slice grid. */ lbnd_in[ 0 ] = 1; ubnd_in[ 0 ] = nchan; lbnd_in[ 1 ] = 1; ubnd_in[ 1 ] = ndet; /* Create a PermMap that can be used to re-order the output axes so that channel number is axis 3. */ outperm[ 0 ] = 2; outperm[ 1 ] = 3; outperm[ 2 ] = 1; inperm[ 0 ] = 3; inperm[ 1 ] = 1; inperm[ 2 ] = 2; pmap = astPermMap( 3, inperm, 3, outperm, NULL, " " ); /* If we are using multiple threads to rebin spectral blocks in parallel, calculate the number of channels that are processed by each thread, and the number of threads to use. The whole output spectrum is divided up into blocks. The number of blocks is two times the number of threads, and each thread rebins two adjacent blocks. Alternate blocks are re-binned simultanously. First, the odd numbered blocks are re-binned (one by each thread). When all odd numbered blocks have been re-binned, the even numbered blocks are re-binned. We ensure that the number of threads used results in a block size that is larger than the spreading width produced by the requested spreading scheme. This means that no pair of simultanously executing threads will ever try to write to the same channel of the output spectrum. */ maxthreads = wf ? wf->nworker : 1; if( maxthreads > MAXTHREADS ) maxthreads = MAXTHREADS; if( maxthreads > 1 ) { /* Find the largest number of threads into which each output spectrum can be split. The limit is imposes by the requirement that each block is larger than the pixel spreading produced by the requested spreading scheme. */ nthreads = ( ( dim[ 2 ] + 1 )/2 )/smf_spreadwidth( spread, params, status ); /* If the spectral range is less than twice the spreading width, we cannot use multiple threads. */ if( nthreads > 1 ) { /* Restrict the number of threads to be no more than the number of workers available in the work force. */ if( nthreads > maxthreads ) nthreads = maxthreads; if( data->file ) { msgOutiff( MSG__DEBUG, " ", "smf_rebincube_ast: Using %d threads " "to process data file '%s'.", status, nthreads, data->file->name ); } /* Find the number of output channels in each spectral block. */ blk_size = ( dim[ 2 ] - 1 )/( 2*nthreads ) + 1; /* Set up the first output channel number within each block. */ nblock = 2*nthreads; for( iblock = 0; iblock < nblock; iblock++ ) { blk_bot[ iblock ] = (double) ( iblock*blk_size + 1 ); } /* Add in the first channel number beyond the last block. */ blk_bot[ nblock ] = blk_bot[ nblock - 1 ] + blk_size; /* If the output spectrum is too short to guarantee that there are any independent blocks of output channels, we process the whole spectrum in a single thread. */ } else { if( data->file ) { msgOutiff( MSG__DEBUG, " ", "smf_rebincube_ast: Using one thread " "to process data file '%s'.", status, data->file->name ); } nthreads = 1; nblock = 1; blk_bot[ 0 ] = 1.0; blk_bot[ 1 ] = (double) ( dim[ 2 ] + 1 ); } /* If multiple threads are not available, we process the whole spectrum in a single thread. */ } else { nthreads = 1; nblock = 1; blk_bot[ 0 ] = 1.0; blk_bot[ 1 ] = (double) ( dim[ 2 ] + 1 ); } /* Convert the block boundaries from output channel numbers into input channel numbers. */ astTran1( ssmap, nblock + 1, blk_bot, 0, blk_bot ); /* Ensure they are in increasing order, and are not outside the bounds of the input array. */ if( blk_bot[ 0 ] > blk_bot[ 1 ] ) { for( iblock = 0; iblock < ( nblock + 1 )/2; iblock++ ) { dtemp = blk_bot[ nblock - iblock ]; blk_bot[ nblock - iblock ] = blk_bot[ iblock ]; blk_bot[ iblock ] = dtemp; } } for( iblock = 0; iblock <= nblock; iblock++ ) { if( blk_bot[ iblock ] < 1 ) { blk_bot[ iblock ] = 1.0; } else if( blk_bot[ iblock ] > nchan ) { blk_bot[ iblock ] = nchan; } } /* Count the number of time slices to be processed. */ if( ptime ) { itime = 0; while( ptime[ itime ] != VAL__MAXI ) itime++; if( data->file ) { msgOutiff( MSG__DEBUG, " ", "smf_rebincube_ast: Selecting %d time " "slices from data file '%s'.", status, (int) itime, data->file->name ); } } else { itime = nslice; if( data->file ) { msgOutiff( MSG__DEBUG, " ", "smf_rebincube_ast: Using all %d time " "slices from data file '%s'.", status, (int) itime, data->file->name ); } } /* Initialise a pointer to the next time slice index to be used. */ nexttime = ptime; /* Initialise the progress meter. */ smf_reportprogress( itime, status ); /* Loop round all time slices in the input NDF. */ for( itime = 0; itime < nslice && *status == SAI__OK; itime++ ) { /* If this time slice is not being pasted into the output cube, pass on. */ if( nexttime ){ if( *nexttime != (int) itime ) continue; nexttime++; } /* Store a pointer to the first input data value in this time slice. */ tdata = ( (float *) (data->pntr)[ 0 ] ) + itime*timeslice_size; /* Begin an AST context. Having this context within the time slice loop helps keep the number of AST objects in use to a minimum. */ astBegin; /* Get a Mapping from the spatial GRID axes in the input the spatial GRID axes in the output for the current time slice. Note this has to be done first since it stores details of the current time slice in the "smfHead" structure inside "data", and this is needed by subsequent functions. */ totmap = smf_rebin_totmap( data, itime, abskyfrm, oskymap, moving, NO_FTS, status ); if( !totmap ) { if( data->file ) { msgOutiff( MSG__DEBUG, " ", "smf_rebincube_ast: Cannot get " "Mapping for slice %d from data file '%s'.", status, (int) itime, data->file->name ); } break; } /* Get the effective exposure time, the total exposure time, and the Tsys->Variance onversion factor for this time slice. Also get a pointer to the start of the Tsys array. */ tsys = smf_rebincube_tcon( hdr, itime, fcon, &texp, &teff, &tcon, status ); /* So "totmap" is a 2-input, 2-output Mapping that transforms the input spatial GRID coords into output spatial GRID coords. In order to speed up astRebinSeq we represent this by a pair of parallel LutMaps. To do this (using atlTolut) we need a Mapping which only has 1 input, so we preceed "totmap" with "detmap" (which also has the effect of exluding data from unrequired detectors). We then combine this Mapping in parallel with the spectral LutMap to get a 2-input (channel number, detector index) and 3-output (output grid coords) Mapping. We finally add a PermMap to re-arrange the output axes so that channel number is axis 3 in the output. */ dtotmap = (AstMapping *) astCmpMap( detmap, totmap, 1, " " ); if( ndet > 1 ) { atlTolut( dtotmap, 1.0, (double) ndet, 1.0, "LutInterp=1", &splut, status ); } else { splut = astClone( dtotmap ); } fullmap = astSimplify( astCmpMap( astCmpMap( sslut, splut, 0, " " ), pmap, 1, " " ) ); /* If required calculate the variance associated with each value in the current time slice. based on the input Tsys values. If they are needed, but not available, ignored the time slice. */ ignore = 0; if( varwork ) { ignore = 1; vp = varwork; for( idet = 0; idet < ndet; idet++ ) { invar = VAL__BADR; rtsys = tsys ? (float) tsys[ idet ] : VAL__BADR; if( rtsys <= 0.0 ) rtsys = VAL__BADR; if( rtsys != VAL__BADR ) { *good_tsys = 1; if( tcon != VAL__BADD ) { invar = tcon*rtsys*rtsys; ignore = 0; } } for( ichan = 0; ichan < nchan; ichan++ ) *(vp++) = invar; } } /* Unless we are ignoring this time slice, paste it into the 3D output cube. The smf_rebincube_seqf function is a wrapper for astRebinSeqF that splits the total job up between "nthreads" threads running in parallel. */ if( !ignore ) { smf_rebincube_seqf( wf, nthreads, blk_bot, fullmap, 0.0, 2, lbnd_in, ubnd_in, tdata, varwork, spread, params, ast_flags, 0.0, 50, VAL__BADR, 3, ldim, udim, lbnd_in, ubnd_in, data_array, var_array, wgt_array, nused, status ); /* Now we update the total exposure time array. Scale the exposure time of this time slice in order to reduce its influence on the output expsoure times if it does not have much spectral overlap with the output cube. then fill the 1D work array with this constant value and paste it into the 2D texp_array using the spatial mapping. Note we want the simple sum of the exposure times, with no normalisation. SO we use the AST__NONORM flag which means we do not need to supply a weights array. */ if( texp != VAL__BADR ) { texp *= tfac; for( iv = 0; iv < ndet; iv++ ) detwork[ iv ] = texp; astRebinSeqF( splut, 0.0, 1, ldim, uddim, detwork, NULL, spread, params, AST__NONORM, 0.0, 50, VAL__BADR, 2, ldim, udim, ldim, uddim, texp_array, NULL, NULL, NULL ); } /* Now do the same with the effective exposure time. */ if( teff != VAL__BADR ) { teff *= tfac; for( iv = 0; iv < ndet; iv++ ) detwork[ iv ] = teff; astRebinSeqF( splut, 0.0, 1, ldim, uddim, detwork, NULL, spread, params, AST__NONORM, 0.0, 50, VAL__BADR, 2, ldim, udim, ldim, uddim, teff_array, NULL, NULL, NULL ); } } else if( data->file ) { msgOutiff( MSG__DEBUG, " ", "smf_rebincube_ast: Time slice %d " "is being ignored when processing data file '%s'.", status, (int) itime, data->file->name ); } /* Update the progress meter. */ smf_reportprogress( 0, status ); /* End the AST context. */ astEnd; } /* If this is the final pass through this function, normalise the returned data and variance values. */ if( last ) { /* Check some data was pasted into the output. */ if( *nused > 0 ) { /* Create a dummy mapping that can be used with astRebinSeq (it is not actually used for anything since we are not adding any more data into the output arrays). */ fullmap = (AstMapping *) astPermMap( 2, NULL, 3, NULL, NULL, " " ); /* Normalise the data values. We do not normalise the exposure time arrays. */ astRebinSeqF( fullmap, 0.0, 2, lbnd_in, ubnd_in, NULL, NULL, spread, params, AST__REBINEND | ast_flags, 0.0, 50, VAL__BADR, 3, ldim, udim, lbnd_in, ubnd_in, data_array, var_array, wgt_array, nused ); fullmap = astAnnul(fullmap); /* If no data was pasted into the output, fill it with bad values and issue a warning. */ } else { size_t nel = dim[0]*dim[1]*dim[2]; size_t iel; float *p1 = data_array; for( iel = 0; iel < nel; iel++ ) *(p1++) = VAL__BADR; if( genvar ) { p1 = var_array; for( iel = 0; iel < nel; iel++ ) *(p1++) = VAL__BADR; } msgOut( "", "WARNING: No good values in output cube.", status ); } } /* Free resources. */ detlut = astFree( detlut ); detwork = astFree( detwork ); varwork = astFree( varwork ); }
void cupid_mon( int *status ) { /* *+ * Name: * cupid_mon * Purpose: * Top-level CUPID function for A-task monolith on UNIX. * Language: * Starlink C * Type of Module: * ADAM A-task * Description: * This is the top-level A-task monolith function for the CUPID * suite of A-tasks. Each CUPID command is an alias to a softlink * that points to this monolith. The chosen command is obtained * from the ADAM routine TASK_GET_NAME. The command may be specified * from the shell or ICL. Given the command, the requested A-task * is called after a successful matching of the input string with a * valid task name. If there is no match, an error report is made. * Parameters: * status * Pointer to the global status variable used by the ADAM fixed part. * Synopsis: * void cupid_mon( int *status ); * Copyright: * Copyright (C) 2009 Science & Technology Facilities Council. * Copyright (C) 2005 Particle Physics & Astronomy Research Council. * All Rights Reserved. * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (STARLINK) * TIMJ: Tim Jenness (JAC, Hawaii) * {enter_new_authors_here} * History: * 28-SEP-2005 (DSB): * Original version. * 29-JUL-2009 (TIMJ): * Call taskGetName rather than Fortran. * Add CUPID and version number to NDF history. * 31-JUL-2009 (DSB): * Use ndgBegpv/Endpv to provide automatic provenance propagation. * 16-OCT-2009 (DSB): * Use ndgBeggh/ndgEndgh to record contents of group parameters in * the history component of output NDFs. * 2011-01-19 (TIMJ): * Add leak checking to CUPID monolith * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local variables: */ char appname[NDF__SZAPP+1]; /* Application name for NDF History */ char buff[PAR__SZNAM+7]; /* Application name for provenance handling */ char filter[PAR__SZNAM+PAR__SZNAM+1]; char name[PAR__SZNAM+1]; /* C character variable to hold name */ int ast_caching; /* Initial value of AST MemoryCaching tuning parameter */ int emslev1; /* EMS level on entry */ int emslev2; /* EMS level on exit */ int ngrp0; /* Number of grp ids at start */ int ngrp1; /* Number of grp ids at end */ int nloc0; /* Number of active HDS Locators at start */ int nloc1; /* Number of active HDS Locators at end */ /* Check the inherited status. */ if( *status != SAI__OK ) return; /* For debugging, watch one of the leaked GRP identifiers listed by the call to grpWatch at the end of this routine (if any). */ /* grpWatch( 3129345, status ); */ /* Read the input error message stack level */ emsLevel( &emslev1 ); /* Obtain the command from the environment. This returns uppercase names. */ taskGetName( name, sizeof(name), status ); /* Update the application name in the NDF history recording to include the version number of the application */ snprintf( appname, NDF__SZAPP, "%-*s (%s V%s)", PAR__SZNAM, name, PACKAGE_UPCASE, PACKAGE_VERSION); ndfHappn( appname, status ); /* Make AST use the same variable for its inherited status. */ astWatch( status ); /* Tell AST to re-cycle memory when possible. */ ast_caching = astTune( "MemoryCaching", 1 ); /* Get the GRP and HDS status for leak checking - need the task name to mask out parameter names. Also need to mask out the monlith name */ one_strlcpy( filter, "!CUPID_MON,!", sizeof(filter), status); one_strlcat( filter, name, sizeof(filter), status ); grpInfoi( NULL, 0, "NGRP", &ngrp0, status ); hdsInfoI( NULL, "LOCATORS", filter, &nloc0, status ); /* Begin a provenance block. This causes event handlers to be registered with the NDF library so that a handler routine in NDG is called every time an NDF is opened. This handler routine keeps a record of all NDFs that are opened for input or output, until the block is closed by calling ndgEndpv. */ ndgBegpv( status ); /* Begin a GRP NDF history block. This causes the contents of GRP groups to be appended to default history text added to any NDFs during the block. */ ndgBeggh( status ); /* Check the string against valid A-task names---if matched then call the relevant A-task. */ /* Finds a low frequency background surface. */ if( !strcmp( name, "FINDBACK" ) ) { findback( status ); /* Identifies emission clumps within a 2- or 3D NDF. */ } else if( !strcmp( name, "FINDCLUMPS" ) ) { findclumps( status ); /* Give help on CUPID commands. */ } else if( !strcmp( name, "CUPIDHELP" ) ) { cupidhelp( status ); /* Create simulated data containing clumps and noise. */ } else if( !strcmp( name, "MAKECLUMPS" ) ) { makeclumps( status ); /* Extract clump parameters from another image */ } else if( !strcmp( name, "EXTRACTCLUMPS" ) ) { extractclumps( status ); /* Obtain information about one or more clumps. */ } else if( !strcmp( name, "CLUMPINFO" ) ) { clumpinfo( status ); /* Report an error if the command name is not recognised. */ } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRep( "CUPID_MON_NOCOM", "CUPID: No such command ^CMD.", status ); } /* End the GRP NDF history block. */ ndgEndgh( status ); /* End the provenance block. This will result in every output NDF being given a provenance extension containing a record of the input NDFs that the application accessed in order to create the output NDF. Any output NDF that already contains a provenance extension is left unchanged (so individual application can override this automatic provenance handling by adding a provenance extension to the output NDF itself). */ sprintf( buff, "CUPID:%s", name ); ndgEndpv( buff, status ); /* Re-instate the original value of the AST ObjectCaching tuning parameter. */ astTune( "MemoryCaching", ast_caching ); /* Check for GRP leaks Do this in a new error reporting context so that we get the correct value even if an error has occurred. */ errBegin( status ); grpInfoi( NULL, 0, "NGRP", &ngrp1, status ); /* If there are more active groups now than there were on entry, there must be a problem (GRP identifiers are not being freed somewhere). So report it. */ if (*status == SAI__OK && ngrp1 > ngrp0) { msgBlank( status ); msgSetc( "NAME", name ); msgSeti( "NGRP0", ngrp0 ); msgSeti( "NGRP1", ngrp1 ); msgOut( " ", "WARNING: The number of active " "GRP identifiers increased from ^NGRP0 to ^NGRP1 " "during execution of ^NAME (" PACKAGE_UPCASE " programming " " error).", status); msgBlank(status); grpWatch( 0, status ); } errEnd( status ); /* Check for HDS leaks Do this in a new error reporting context so that we get the correct value even if an error has occurred. */ errBegin( status ); hdsInfoI( NULL, "LOCATORS", filter, &nloc1, status ); /* If there are more active locators now than there were on entry, there must be a problem (HDS locators are not being freed somewhere). So report it. */ if (*status == SAI__OK && nloc1 > nloc0) { msgBlank( status ); msgSetc( "NAME", name ); msgSeti( "NLOC0", nloc0 ); msgSeti( "NLOC1", nloc1 ); msgOut( " ", "WARNING: The number of active " "HDS Locators increased from ^NLOC0 to ^NLOC1 " "during execution of ^NAME (" PACKAGE_UPCASE " programming " " error).", status); msgBlank(status); hdsShow("LOCATORS", status); hdsShow("FILES", status); } errEnd( status ); /* Read the exitt error message stack level */ emsLevel( &emslev2 ); if (*status == SAI__OK && emslev1 != emslev2 ) { errMark(); msgBlank( status ); msgSetc( "NAME", name ); msgSeti( "LV1", emslev1); msgSeti( "LV2", emslev2); msgOut( " ", "WARNING: EMS Stack level went from ^LV1 to ^LV2" " during execution of ^NAME (" PACKAGE_UPCASE " programming" " error).", status ); msgBlank(status); errRlse(); } /* Make AST use its own internal variable for its inherited status. */ astWatch( NULL ); /* Clear out any remaining memory allocated by AST and report unintentional leaks. */ astFlushMemory( 1 ); }
HRESULT CActorConnector::ProcessIncomingMsg( CMBCSocket* pMBCSock, int nMsgType, char* bufferIn, int nUsed ) { // Actor处理 if (nMsgType == embmsgtype_DispatchToActorMsg) { ST_EMBTRANSMSG msgIn(nMsgType); UnPackMBCMsg(bufferIn, nUsed, msgIn); if (m_pITaskCommit) { CString strRet; // 解析消息类型 m_pITaskCommit->OnActorConnectorMsg(msgIn.strData, strRet); if (!strRet.IsEmpty()) { ST_EMBTRANSMSG msgOut(embmsgtype_ActorToDispatchMsg); msgOut.strGuid = msgIn.strGuid; msgOut.strData = strRet; CEMBAutoBuffer szbuff(msgOut); int nRetUsed = 0; PackMBCMsg(msgOut, szbuff, szbuff.GetSize(), nRetUsed); //send back to dispatch HRESULT hr = send(*pMBCSock, szbuff, nRetUsed, 0); if (hr == SOCKET_ERROR) { hr = WSAGetLastError(); ASSERT(FALSE); } else { hr = S_OK; } } } } else if (nMsgType == embmsgtype_ActorReportGuid) { CFWriteLog(0, TEXT("dispatch request actorid")); ST_EMBTRANSMSG msgIn(nMsgType); CTxStrConvert val; val.SetVal(m_nActorId); msgIn.strData = val.GetAsString(); // 本机电脑名 char pcName[128]; gethostname(pcName, sizeof(pcName)); msgIn.strPcName = pcName; CEMBAutoBuffer szbuff(msgIn); int nRetUsed = 0; PackMBCMsg(msgIn, szbuff, szbuff.GetSize(), nRetUsed); //send back to dispatch HRESULT hr = send(*pMBCSock, szbuff, nRetUsed, 0); if(hr == SOCKET_ERROR) { hr = WSAGetLastError(); ASSERT(FALSE); } } else { return __super::ProcessIncomingMsg(pMBCSock, nMsgType, bufferIn, nUsed); } return S_OK; }
void clumpinfo( int *status ) { /* *+ * Name: * CLUMPINFO * Purpose: * Obtain information about one or more previously identified clumps. * Language: * C * Type of Module: * ADAM A-task * Description: * This application returns various items of information about a * single clump, or a collection of clumps, previously identified * using FINDCLUMPS or EXTRACTCLUMPS. * Usage: * clumpinfo ndf clumps quiet * ADAM Parameters: * CLUMPS = LITERAL (Read) * Specifies the indices of the clumps to be included in the * returned information. It can take any of the following values: * * - "ALL" or "*" -- All clumps. * * - "xx,yy,zz" -- A list of clump indices. * * - "xx:yy" -- Clump indices between xx and yy inclusively. When * xx is omitted the range begins from one; when yy is omitted the * range ends with the final clump index. * * - Any reasonable combination of above values separated by * commas. * FLBND( ) = _DOUBLE (Write) * The lower bounds of the bounding box enclosing the selected * clumps in the current WCS Frame of the input NDF. Celestial axis * values are always in units of radians, but spectral axis units * will be in the spectral units used by the current WCS Frame. * FUBND( ) = _DOUBLE (Write) * The upper bounds of the bounding box enclosing the selected * clumps. See parameter FLBND for more details. * LBOUND( ) = _INTEGER (Write) * The lower pixel bounds of bounding box enclosing the selected * clumps. * NCLUMPS = _INTEGER (Write) * The total number of clumps descrriptions stored within the supplied * NDF. * NDF = NDF (Read) * The NDF defining the previously identified clumps. This * should contain a CUPID extension describing all the identified * clumps, in the format produced by FINDCLUMPS or EXTRACTCLUMPS. * QUIET = _LOGICAL (Read) * If TRUE, then no information is written out to the screen, * although the output parameters are still assigned values. [FALSE] * UBOUND( ) = _INTEGER (Write) * The upper pixel bounds of bounding box enclosing the selected * clumps. * Notes: * - It is hoped to extend the range of information reported by this * application as new requirements arise. * Synopsis: * void clumpinfo( int *status ); * Copyright: * Copyright (C) 2007 Particle Physics & Astronomy Research Council. * All Rights Reserved. * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry * {enter_new_authors_here} * History: * 22-MAR-2007 (DSB): * Original version. * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables: */ AstFrame *cfrm; /* Pointer to current WCS Frame */ AstMapping *cmap; /* Pointer to PIXEL->current Frame Mapping */ CupidClumpInfo info; /* Structure holding returned information */ Grp *grp = NULL; /* GRP group holding input NDF name */ HDSLoc *aloc = NULL; /* Locator for CLUMPS array in CUPID extension */ HDSLoc *cloc = NULL; /* Locator for a single CLUMP structure */ HDSLoc *xloc = NULL; /* Locator for CUPID extension */ char *p; /* Pointer into tmpstr string */ char tmpstr[ 100 ]; /* Buffer for temporary strings */ const char *dom; /* Pointer to axis Domain name */ double flbnd[ NDF__MXDIM ]; /* Lower bounds of WCS bounding box */ double fubnd[ NDF__MXDIM ]; /* Upper bounds of WCS bounding box */ double plbnd[ NDF__MXDIM ]; /* Lower bounds of PIXEL bounding box */ double pubnd[ NDF__MXDIM ]; /* Upper bounds of PIXEL bounding box */ int *clump_flags = NULL; /* Flags indicating if each clump is to be used */ int *clump_indices = NULL;/* List of indices of clumps to be used */ int i; /* Loop count */ int iclump; /* One-based clump index */ int indf; /* NDF identifier for input NDF */ int ipix; /* Index of PIXEL Frame */ size_t nclumps; /* No. of clump descriptions within the supplied NDF */ int nuse; /* Number of clumps to be used */ int primary; /* Value for locator primary flag */ int quiet; /* Supress screen output? */ size_t size; /* Number of values in group "*grp" */ int there; /* Does the enquired object exist? */ /* Abort if an error has already occurred. */ if( *status != SAI__OK ) return; /* Begin an AST context */ astBegin; /* Start an NDF context */ ndfBegin(); /* Obtain the input NDF and get a locator for the array of clump descriptions within it. ----------------------------------------------------------------- */ /* Get an identifier for the input NDF. We use NDG (via kpg1_Rgndf) instead of calling ndfAssoc directly since NDF/HDS has problems with file names containing spaces, which NDG does not have. */ kpg1Rgndf( "NDF", 1, 1, "", &grp, &size, status ); ndgNdfas( grp, 1, "READ", &indf, status ); grpDelet( &grp, status ); /* Check the NDF has a suitable CUPID extension containing an array of clump cut-outs. Get an HDS locator for the array. */ ndfXstat( indf, "CUPID", &there, status ); if( !there ) { if( *status == SAI__OK ) { *status = SAI__ERROR; ndfMsg( "NDF", indf ); errRep( "", "The NDF \"^NDF\" does not contain a CUPID extension " "such as created by FINDCLUMPS or EXTRACTCLUMPS.", status ); } } else { ndfXloc( indf, "CUPID", "READ", &xloc, status ); datThere( xloc, "CLUMPS", &there, status ); if( !there ) { if( *status == SAI__OK ) { *status = SAI__ERROR; ndfMsg( "NDF", indf ); errRep( "", "The CUPID extension within NDF \"^NDF\" does not " "contain an array of clumps such as created by " "FINDCLUMPS or EXTRACTCLUMPS.", status ); } } else { datFind( xloc, "CLUMPS", &aloc, status ); primary = 1; datPrmry( 1, &aloc, &primary, status ); } datAnnul( &xloc, status ); } /* Abort if we have no clumps array locator, or if an error occurred. */ if( !aloc || *status != SAI__OK ) goto L999; /* Calculate the required clump information, and store it in the "info" structure. ----------------------------------------------------------------- */ /* Indicate that the structure holding the returned information has not yet been initialised. */ info.init = 0; /* Get the WCS FrameSet from the input NDF, and store a pointer to it in the "info" structure. */ kpg1Gtwcs( indf, &(info.iwcs), status ); /* Get the number of clumps defined within the input NDF. */ datSize( aloc, &nclumps, status ); /* Get the list of clump indices to iclude in the returned information. */ clump_flags = astMalloc( sizeof( int )*nclumps ); clump_indices = astMalloc( sizeof( int )*nclumps ); kpg1Gilst( 1, (int) nclumps, (int) nclumps, "CLUMPS", clump_flags, clump_indices, &nuse, status ); /* Loop round all clumps that are to be used. */ for( i = 0; i < nuse && *status == SAI__OK; i++ ) { iclump = clump_indices[ i ]; /* Get a locator for this clump. */ datCell( aloc, 1, &iclump, &cloc, status ); /* Update the returned information to include this clump. */ cupidClumpInfo1( cloc, &info, status ); /* Annul the clump structure locator. */ datAnnul( &cloc, status ); } /* Write out the information to the screen and to appropriate output parameters. ----------------------------------------------------------------- */ /* See if screen output is required. */ parGet0l( "QUIET", &quiet, status ); if( !quiet ) msgBlank( status ); /* The number of clumps defined within the input NDF... */ parPut0i( "NCLUMPS", (int) nclumps, status ); if( ! quiet ) { msgSeti( "NCLUMPS", (int) nclumps ); msgOut( "", " Total no. of clumps: ^NCLUMPS", status ); } /* Pixel index bounding box... */ parPut1i( "LBOUND", info.npix, info.lbnd, status ); parPut1i( "UBOUND", info.npix, info.ubnd, status ); if( !quiet ) { p = tmpstr + sprintf( tmpstr, "( " ); for( i = 0; i < info.npix; i++) { p += sprintf( p, "%d:%d", info.lbnd[ i ], info.ubnd[ i ] ); if( i < info.npix - 1 ) p += sprintf( p, ", " ); } p += sprintf( p, " )" ); msgSetc( "SECTION", tmpstr ); msgOut( "", " Pixel index bounding box: ^SECTION", status ); } /* WCS bounding box (first convert the pixel index bounding box into WCS coords)... */ cfrm = astGetFrame( info.iwcs, AST__CURRENT ); kpg1Asffr( info.iwcs, "PIXEL", &ipix, status ); cmap = astGetMapping( info.iwcs, ipix, AST__CURRENT ); for( i = 0; i < info.npix; i++ ) { plbnd[ i ] = info.lbnd[ i ] - 1.0; pubnd[ i ] = info.ubnd[ i ]; } for( i = 0; i < info.nwcs; i++ ) { astMapBox( cmap, plbnd, pubnd, 1, i + 1, flbnd + i, fubnd + i, NULL, NULL); } astNorm( cfrm, flbnd ); astNorm( cfrm, fubnd ); parPut1d( "FLBND", info.nwcs, flbnd, status ); parPut1d( "FUBND", info.nwcs, fubnd, status ); if( !quiet ) { msgOut( "", " WCS bounding box:", status ); for( i = 0; i < info.nwcs; i++) { msgSetc( "L", astFormat( cfrm, i + 1, flbnd[ i ] ) ); msgSetc( "U", astFormat( cfrm, i + 1, fubnd[ i ] ) ); sprintf( tmpstr, "Domain(%d)", i + 1 ); dom = astGetC( cfrm, tmpstr ); if( dom && strcmp( dom, "SKY" ) ) { sprintf( tmpstr, "Unit(%d)", i + 1 ); msgSetc( "UNT", astGetC( cfrm, tmpstr ) ); } else { msgSetc( "UNT", "" ); } sprintf( tmpstr, "Label(%d)", i + 1 ); msgSetc( "LAB", astGetC( cfrm, tmpstr ) ); msgOut( "", " ^LAB: ^L -> ^U ^UNT", status ); } } if( !quiet ) msgBlank( status ); /* Tidy up. -------- */ L999: ; /* Free resources. */ clump_flags = astFree( clump_flags ); clump_indices = astFree( clump_indices ); if( aloc ) datAnnul( &aloc, status ); /* End the NDF context */ ndfEnd( status ); /* End the AST context */ astEnd; /* If an error has occurred, issue another error report identifying the program which has failed (i.e. this one). */ if( *status != SAI__OK ) { errRep( "CLUMPINFO_ERR", "CLUMPINFO: Failed to obtain information " "about one or more previously identified clumps.", status ); } }
//************************************************************************************************************************************************ void checkDoorState() { //the master controller will send values to this analog pin when the doors are open. When closed, the value will be 0 //will need to have 4 door state values. // door 1 = open, door 1 & 2 open, door 2 open. all doors closed d1LimVal = analogRead(door1LimitPin); d2LimVal = analogRead(door2LimitPin); //Serial.print("Limit1Val: "); //Serial.print(d1LimVal); //Serial.print(" Limit2Val: "); //Serial.println(d2LimVal); if ((d1LimVal >= 1000) && (d2LimVal >= 1000)) //both door limit switches are closed. 1023 { d1S = 1; d2S = 1; blink(NotOKLedPin, 100, 1); msgOut(doorStatLEDPin, 1); } else if ((d1LimVal >= 1000) && (d2LimVal < 50)) { d1S = 1; d2S = 0; blink(NotOKLedPin, 100, 1); msgOut(doorStatLEDPin, 1); } else if ((d1LimVal < 50) && (d2LimVal >= 1000)) { d1S = 0; d2S = 1; blink(NotOKLedPin, 100, 1); msgOut(doorStatLEDPin, 1); } else { d1S = 0; d2S = 0; msgOut(doorStatLEDPin, 0); } Blynk.virtualWrite(1, d1S); //sends the state of Garage door 1 - if 1, then open Blynk.virtualWrite(3, d2S); // sends the state of Garage door 2 - if 1, then open //reset the timer values used for pwd entry if (millis() - pwdEntryStartTime > interval) { door_p1 = false, door_p2 = false, door_p3 = false, door_p4 = false; //reset the sliders in the Blynk app - do this after the interval time has elapsed. Blynk.virtualWrite(9, 0); //pwd is no longer valid - update LED to OFF state Blynk.virtualWrite(5, 0); //reset the pwd sliders to 0 Blynk.virtualWrite(6, 0); //reset the pwd sliders to 0 Blynk.virtualWrite(7, 0); //reset the pwd sliders to 0 Blynk.virtualWrite(8, 0); //reset the pwd sliders to 0 pwdEntryStartTime = 0; } if (door_p1 && door_p2 && door_p3 && door_p4) { Blynk.virtualWrite(9, 1); //pwd is correct - illuminate LED } else { Blynk.virtualWrite(9, 0); //pwd is no longer correct - illuminate LED } }
void smurf_sc2filtermap( int *status ) { Grp *fgrp = NULL; /* Output filter group */ smfFilter *filt=NULL; /* Filter */ double filt_edgehigh=0; /* High-pass filter */ double filt_edgelow=0; /* Low-pass filter */ size_t fsize; /* Number of files in fgrp */ size_t i; /* Loop (grp) counter */ smfData *idata; /* Pointer to input smfData */ Grp *igrp = NULL; /* Input group of files */ int isfft=0; /* Are data fft or real space? */ int *mask=NULL; /* Mask indicating where bad data are */ size_t ndata=0; /* Number of pixels in the map */ size_t ndims; /* Number of real space dimensions */ smfData *odata=NULL; /* Pointer to output smfData to be exported */ Grp *ogrp = NULL; /* Output group of files */ size_t outsize; /* Number of files in output group */ size_t size; /* Number of files in input group */ ThrWorkForce *wf = NULL; /* Pointer to a pool of worker threads */ smfData *wrefmap=NULL; /* Whitening reference map */ int whiten; /* Applying whitening filter? */ Grp *wgrp = NULL; /* Whitening reference map group */ size_t wsize; /* Size of wgrp */ int zerobad; /* Zero VAL__BADD before taking FFT? */ /* Main routine */ ndfBegin(); /* Find the number of cores/processors available and create a pool of threads of the same size. */ wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status ); /* Get input file(s) */ kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status ); size = grpGrpsz( igrp, status ); if (size > 0) { int parstate=0; /* ADAM parameter state */ /* Get output file(s) */ kpg1Wgndf( "OUT", igrp, size, size, "More output files required...", &ogrp, &outsize, status ); /* Write out the filter? */ parState( "OUTFILTER", &parstate, status ); if( parstate != PAR__GROUND ) { kpg1Wgndf( "OUTFILTER", igrp, size, size, "More output filter files required...", &fgrp, &fsize, status ); } } /* Are we going to zero bad values first? */ parGet0l( "ZEROBAD", &zerobad, status ); /* High/low-pass filters? */ parGet0d( "FILT_EDGEHIGH", &filt_edgehigh, status ); parGet0d( "FILT_EDGELOW", &filt_edgelow, status ); /* Are we applying a spatial whitening filter? */ parGet0l( "WHITEN", &whiten, status ); if( whiten ) { /* We also need the reference map to measure the whitening filter. We make a deep copy of it so that we can set bad values to 0 etc. */ smfData *tempdata=NULL; kpg1Rgndf( "whiterefmap", 0, 1, "", &wgrp, &wsize, status ); if( (*status == SAI__OK) && (wsize != 1) ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": WHITEREFMAP must be a single reference map", status ); } smf_open_file( wgrp, 1, "READ", SMF__NOTTSERIES, &tempdata, status ); wrefmap = smf_deepcopy_smfData( tempdata, 0, 0, 0, 0, status ); smf_close_file( &tempdata, status ); /* Set VAL__BADD to zero if requested */ if( (*status==SAI__OK) && zerobad ) { double *d=NULL; size_t j; ndata=1; for( j=0; j<wrefmap->ndims; j++ ) ndata *= wrefmap->dims[j]; d = wrefmap->pntr[0]; if( d ) { for( j=0; j<ndata; j++ ) { if( d[j] == VAL__BADD ) { d[j] = 0; } } } } } for( i=1;(*status==SAI__OK)&&i<=size; i++ ) { smf_open_file( igrp, i, "READ", SMF__NOTTSERIES, &idata, status ); isfft = smf_isfft( idata, NULL, NULL, NULL, NULL, &ndims, status); if( (*status==SAI__OK) && isfft ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": Input data are FFT, not real-space!\n", status ); break; } if( (*status==SAI__OK) && (ndims != 2) ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": Input data not a 2D map!\n", status ); break; } /* smf_filter_execute operates in-place, so first create the output data as a copy of the input */ odata = smf_deepcopy_smfData( idata, 0, 0, 0, 0, status ); /* Set VAL__BADD to zero if requested */ if( (*status==SAI__OK) && zerobad ) { double *d=NULL; size_t j, k; ndata=1; for( j=0; j<odata->ndims; j++ ) ndata *= odata->dims[j]; mask = astCalloc( ndata, sizeof(*mask) ); /* Do both DATA and VARIANCE */ if( *status == SAI__OK ) { for( k=0; k<2; k++ ) { d = odata->pntr[k]; if( d ) { for( j=0; j<ndata; j++ ) { if( d[j] == VAL__BADD ) { d[j] = 0; mask[j] = 1; } } } } } } /* Measure and apply the whitening filter. We need to do this every time because the dimensions of filt need to match idata (not the wrefmap) and they might be different each time. We could try to be more clever in the future if this is too slow. */ filt = smf_create_smfFilter( idata, status ); /* Set to the identity in case no whitening is applied */ msgOut( "", TASK_NAME ": initializing filter", status ); smf_filter_ident( filt, 0, status ); if( whiten ) { msgOut( "", TASK_NAME ": whitening the filter", status ); smf_filter2d_whiten( wf, filt, wrefmap, 0, 0, 3, status ); } if( filt_edgelow ) { msgOutf( "", TASK_NAME ": applying low-pass at < %lg 1/arcsec", status, filt_edgelow ); smf_filter2d_edge( filt, filt_edgelow, 1, status ); } if( filt_edgehigh ) { msgOutf( "", TASK_NAME ": applying high-pass at >= %lg 1/arcsec", status, filt_edgehigh ); smf_filter2d_edge( filt, filt_edgehigh, 0, status ); } smf_filter_execute( wf, odata, filt, 0, 0, status ); /* Set bad values from the mask */ if( mask ) { double *d=NULL; size_t j, k; /* Do both DATA and VARIANCE */ for( k=0; k<2; k++ ) { d = odata->pntr[k]; if( d ) { for( j=0; j<ndata; j++ ) { if( mask[j] ) { d[j] = VAL__BADD; } } } } } /* Export the data to a new file */ smf_write_smfData( odata, NULL, NULL, ogrp, i, 0, MSG__NORM, status ); /* Write out filters? */ if( fgrp ) smf_write_smfFilter( filt, NULL, fgrp, i, status ); if( filt ) smf_free_smfFilter( filt, status ); } /* Tidy up after ourselves */ if( fgrp ) grpDelet( &fgrp, status); if( igrp ) grpDelet( &igrp, status); if( ogrp ) grpDelet( &ogrp, status); if( wgrp ) grpDelet( &wgrp, status ); if( odata ) smf_close_file( &odata, status ); if( wrefmap ) smf_close_file( &wrefmap, status ); if( mask ) mask = astFree( mask ); ndfEnd( status ); /* Ensure that FFTW doesn't have any used memory kicking around */ fftw_cleanup(); }
void DDS_B::ProcessRequest(AbstractUnit* pUnit, const MessageAerospace& msg) { // DDS step two (2) // dtMemId defines the initial situation. if(msg.GetDataType()==dtMemId) { // We must send something back to node A. // We will return one of three possibilities. // XOn ... the transfer is accepted. // Abort ... the transfer is busy (can't accept another). // Invalid ... this data structure id is not supported. int32_t iRet = ddsXOn; if(IsBusy()) iRet = ddsAbort; // data id, number of messages else if(!pUnit->AcceptDownload(msg.GetData().ui32, msg.GetMessageCode())) iRet = ddsInvalid; // Make the response message - all nodes will hear this. MessageAerospace msgOut( Identifier(lPrimary, idNS_C00_Response, pUnit->GetNodeId(), msg.GetSender()), dtLong, sDataDownload, msg.GetMessageCode(), Register(iRet) ); // Remember some data if post was successful. if(pUnit->PostMessage(msgOut)) { PRINTF("DDS B - Step 2: iRet = %i\n", iRet); if(iRet==ddsXOn) { pUnit->SetBDownloadTimeout(0, &m_bTimeout); // clear any pending timeout. Reset(); m_eState = sReceivingData; m_bySize = msg.GetMessageCode(); // number of messages to accept m_uiDataId = msg.GetData().ui32; // data structure id m_bySender = msg.GetSender(); // remember the sender. // We do not want to listen forever. Set the timeout. pUnit->SetBDownloadTimeout(TRANSFER_TIMEOUT_MS(m_bySize), &m_bTimeout); return; } } // Can't post a message. else { PRINTF("DDS B: Unable to post a confirmation message.\n"); } } // DDS step five (5) // Receiving data messages and storing them. We may return // a message that will pause/resume or abort the download. // If this is the last message to be received, a CRC is sent // back. See step seven. else if(m_eState == sReceivingData) { //ASSERT(msg.GetMessageCode() == m_byIndex+1); if(msg.GetMessageCode() != m_byIndex+1) { // TODO verify this. m_eState = sInvalidIndex; } else { int32_t iRet = pUnit->StoreDownloadMessage(m_uiDataId, msg); // The data msg was accepted. if(iRet == ddsXOn) { m_byIndex++; UpdateCRC(msg.GetData()); // DDS step seven (7) // This message termiates the download service by // returning CRC value of downloaded data. if(m_byIndex == m_bySize) { MessageAerospace msgOut( Identifier(lPrimary, idNS_C00_Response, pUnit->GetNodeId(), msg.GetSender()), dtChksum, sDataDownload, msg.GetMessageCode(), Register(m_crc.Get()) ); if(pUnit->PostMessage(msgOut)==false) { PRINTF("DDS B: Unable to post final checksum message.\n"); return; } // We are ready to accept new download service. pUnit->SetBDownloadTimeout(0, &m_bTimeout); PRINTF("DDS B: Checksum = 0x%x\n", m_crc.Get()); Reset(); } } // We need to send iRet, because it is not rXOn. // Here we actually implementing step five. else { // TODO Če je xOn po xOff, potem moramo poslati s katerim // indeksom naj node A nadaljuje. MessageAerospace msgOut( Identifier(lPrimary, idNS_C00_Response, pUnit->GetNodeId(), msg.GetSender()), dtLong, sDataDownload, msg.GetMessageCode(), Register(iRet) ); // Is posted successfully, remember some data if(pUnit->PostMessage(msgOut)==false) { PRINTF("DDS B: Unable to post message.\n"); } } } } // We are not in receiving mode anymore - most probaby due timeout. else { PRINTF("DDS B: Message received in sReady mode.\n"); } }
void smurf_unmakemap( int *status ) { /* Local Variables */ AstFrameSet *wcsin = NULL; /* WCS Frameset for input cube */ AstMapping *skymap; /* GRID->SkyFrame Mapping from input WCS */ AstSkyFrame *abskyfrm; /* Input SkyFrame (always absolute) */ AstSkyFrame *skyfrm = NULL;/* SkyFrame from the input WCS Frameset */ Grp *igrp1 = NULL; /* Group of input sky files */ Grp *igrp2 = NULL; /* Group of input template files */ Grp *igrpc = NULL; /* Group of input COM files */ Grp *igrpg = NULL; /* Group of input GAI files */ Grp *igrpq = NULL; /* Group of input Q sky files */ Grp *igrpu = NULL; /* Group of input U sky files */ Grp *ogrp = NULL; /* Group containing output file */ HDSLoc *cloc = NULL; /* HDS locator for component ipdata structure */ HDSLoc *iploc = NULL; /* HDS locator for top level ipdata structure */ ThrWorkForce *wf = NULL; /* Pointer to a pool of worker threads */ char ipdata[ 200 ]; /* Text buffer for IPDATA value */ char pabuf[ 10 ]; /* Text buffer for parameter value */ char subarray[ 5 ]; /* Name of SCUBA-2 subarray (s8a,s8b,etc) */ dim_t iel; /* Index of next element */ dim_t ndata; /* Number of elements in array */ dim_t ntslice; /* Number of time slices in array */ double *ang_data = NULL; /* Pointer to the FP orientation angles */ double *angc_data = NULL; /* Pointer to the instrumental ANGC data */ double *c0_data = NULL; /* Pointer to the instrumental C0 data */ double *gai_data = NULL; /* Pointer to the input GAI map */ double *in_data = NULL; /* Pointer to the input I sky map */ double *inc_data = NULL; /* Pointer to the input COM data */ double *inq_data = NULL; /* Pointer to the input Q sky map */ double *inu_data = NULL; /* Pointer to the input U sky map */ double *outq_data = NULL; /* Pointer to the Q time series data */ double *outu_data = NULL; /* Pointer to the U time series data */ double *p0_data = NULL; /* Pointer to the instrumental P0 data */ double *p1_data = NULL; /* Pointer to the instrumental P1 data */ double *pd; /* Pointer to next element */ double *pq = NULL; /* Pointer to next Q time series value */ double *pu = NULL; /* Pointer to next U time series value */ double *qinst_data = NULL; /* Pointer to the instrumental Q data */ double *uinst_data = NULL; /* Pointer to the instrumental U data */ double amp16; /* Amplitude of 16 Hz signal */ double amp2; /* Amplitude of 2 Hz signal */ double amp4; /* Amplitude of 4 Hz signal */ double angrot; /* Angle from focal plane X axis to fixed analyser */ double paoff; /* WPLATE value corresponding to POL_ANG=0.0 */ double params[ 4 ]; /* astResample parameters */ double phase16; /* Phase of 16 Hz signal */ double phase2; /* Phase of 2 Hz signal */ double phase4; /* Phase of 4 Hz signal */ double sigma; /* Standard deviation of noise to add to output */ int alignsys; /* Align data in the map's system? */ int cdims[ 3 ]; /* Common-mode NDF dimensions */ int dims[ NDF__MXDIM ]; /* NDF dimensions */ int flag; /* Was the group expression flagged? */ int gdims[ 3 ]; /* GAI model NDF dimensions */ int harmonic; /* The requested harmonic */ int ifile; /* Input file index */ int indf; /* Input sky map NDF identifier */ int indfangc; /* IP ANGC values NDF identifier */ int indfc0; /* IP C0 values NDF identifier */ int indfc; /* Input COM NDF identifier */ int indfcs; /* NDF identifier for matching section of COM */ int indfg; /* Input GAI NDF identifier */ int indfin; /* Input template cube NDF identifier */ int indfiq; /* Input instrumental Q NDF */ int indfiu; /* Input instrumental U NDF */ int indfout; /* Output cube NDF identifier */ int indfp0; /* IP P0 values NDF identifier */ int indfp1; /* IP P1 values NDF identifier */ int indfq; /* Input Q map NDF identifier */ int indfu; /* Input U map NDF identifier */ int interp = 0; /* Pixel interpolation method */ int lbndc[ 3 ]; /* Array of lower bounds of COM NDF */ int moving; /* Is the telescope base position changing? */ int ndim; /* Number of pixel axes in NDF */ int ndimc; /* Number of pixel axes in common-mode NDF */ int ndimg; /* Number of pixel axes in GAI NDF */ int nel; /* Number of elements in array */ int nelc; /* Number of elements in COM array */ int nelg; /* Number of elements in GAI array */ int nelqu; /* Number of elements in Q or U array */ int ngood; /* No. of good values in putput cube */ int nparam = 0; /* No. of parameters required for interpolation scheme */ int pasign; /* Indicates sense of POL_ANG value */ int sdim[ 2 ]; /* Array of significant pixel axes */ int slbnd[ 2 ]; /* Array of lower bounds of input map */ int subnd[ 2 ]; /* Array of upper bounds of input map */ int ubndc[ 3 ]; /* Array of upper bounds of COM NDF */ size_t ncom; /* Number of com files */ size_t ngai; /* Number of gai files */ size_t nskymap; /* Number of supplied sky cubes */ size_t outsize; /* Number of files in output group */ size_t size; /* Number of files in input group */ smfData *odata = NULL; /* Pointer to output data struct */ /* Check inherited status */ if( *status != SAI__OK ) return; /* Begin an AST context */ astBegin; /* Begin an NDF context. */ ndfBegin(); /* Find the number of cores/processors available and create a pool of threads of the same size. */ wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status ); /* Get an identifier for the input NDF. We use NDG (via kpg1Rgndf) instead of calling ndfAssoc directly since NDF/HDS has problems with file names containing spaces, which NDG does not have. */ kpg1Rgndf( "IN", 1, 1, "", &igrp1, &nskymap, status ); ndgNdfas( igrp1, 1, "READ", &indf, status ); /* Map the data array in the input sky map. */ ndfMap( indf, "DATA", "_DOUBLE", "READ", (void **) &in_data, &nel, status ); /* Get the WCS FrameSet from the sky map, together with its pixel index bounds. */ kpg1Asget( indf, 2, 0, 1, 1, sdim, slbnd, subnd, &wcsin, status ); /* Check the current Frame is a SKY frame. */ skyfrm = astGetFrame( wcsin, AST__CURRENT ); if( !astIsASkyFrame( skyfrm ) && *status == SAI__OK ) { ndfMsg( "N", indf ); *status = SAI__ERROR; errRep( " ", " Current Frame in ^N is not a SKY Frame.", status ); } /* Get a copy of the current frame that represents absolute coords rather than offsets. We assume the target is moving if the map represents offsets. */ moving = ( *status == SAI__OK && !strcmp( astGetC( skyfrm, "SkyRefIs" ), "Origin" ) ) ? 1 : 0; abskyfrm = astCopy( skyfrm ); astClear( abskyfrm, "SkyRefIs" ); /* If the ALIGNSYS parameter is TRUE then we align the raw data with the map in the current system of the map, rather than the default ICRS. */ parGet0l( "ALIGNSYS", &alignsys, status ); if( alignsys ) astSetC( abskyfrm, "AlignSystem", astGetC( abskyfrm, "System" ) ); /* Get the Mapping from the Sky Frame to grid axis in the iput map. */ skymap = astGetMapping( wcsin, AST__CURRENT, AST__BASE ); /* Get the pixel interpolation scheme to use. */ parChoic( "INTERP", "NEAREST", "NEAREST,LINEAR,SINC," "SINCSINC,SINCCOS,SINCGAUSS,SOMB,SOMBCOS", 1, pabuf, 10, status ); if( !strcmp( pabuf, "NEAREST" ) ) { interp = AST__NEAREST; nparam = 0; } else if( !strcmp( pabuf, "LINEAR" ) ) { interp = AST__LINEAR; nparam = 0; } else if( !strcmp( pabuf, "SINC" ) ) { interp = AST__SINC; nparam = 1; } else if( !strcmp( pabuf, "SINCSINC" ) ) { interp = AST__SINCSINC; nparam = 2; } else if( !strcmp( pabuf, "SINCCOS" ) ) { interp = AST__SINCCOS; nparam = 2; } else if( !strcmp( pabuf, "SINCGAUSS" ) ) { interp = AST__SINCGAUSS; nparam = 2; } else if( !strcmp( pabuf, "SOMB" ) ) { interp = AST__SOMB; nparam = 1; } else if( !strcmp( pabuf, "SOMBCOS" ) ) { interp = AST__SOMBCOS; nparam = 2; } else if( *status == SAI__OK ) { nparam = 0; *status = SAI__ERROR; msgSetc( "V", pabuf ); errRep( "", "Support not available for INTERP = ^V (programming " "error)", status ); } /* Get an additional parameter vector if required. */ if( nparam > 0 ) parExacd( "PARAMS", nparam, params, status ); /* Get a group of reference time series files to use as templates for the output time series files.*/ ndgAssoc( "REF", 1, &igrp2, &size, &flag, status ); /* Get output file(s) */ kpg1Wgndf( "OUT", igrp2, size, size, "More output files required...", &ogrp, &outsize, status ); /* Get he noise level to add to the output data. */ parGet0d( "SIGMA", &sigma, status ); /* Get any Q and U input maps. */ if( *status == SAI__OK ) { kpg1Rgndf( "QIN", 1, 1, "", &igrpq, &nskymap, status ); ndgNdfas( igrpq, 1, "READ", &indfq, status ); ndfMap( indfq, "DATA", "_DOUBLE", "READ", (void **) &inq_data, &nelqu, status ); if( nelqu != nel && *status == SAI__OK ) { ndfMsg( "Q", indfq ); *status = SAI__ERROR; errRep( "", "Q image '^Q' is not the same size as the I image.", status ); } kpg1Rgndf( "UIN", 1, 1, "", &igrpu, &nskymap, status ); ndgNdfas( igrpu, 1, "READ", &indfu, status ); ndfMap( indfu, "DATA", "_DOUBLE", "READ", (void **) &inu_data, &nelqu, status ); if( nelqu != nel && *status == SAI__OK ) { ndfMsg( "U", indfu ); *status = SAI__ERROR; errRep( "", "U image '^U' is not the same size as the I image.", status ); } if( *status == PAR__NULL ) { ndfAnnul( &indfq, status ); ndfAnnul( &indfu, status ); inq_data = NULL; inu_data = NULL; errAnnul( status ); } else { parGet0d( "ANGROT", &angrot, status ); parGet0d( "PAOFF", &paoff, status ); parGet0l( "PASIGN", &pasign, status ); } } /* Get any common-mode files. */ if( *status == SAI__OK ) { kpg1Rgndf( "COM", size, size, "", &igrpc, &ncom, status ); if( *status == PAR__NULL ) { errAnnul( status ); ncom = 0; } } /* Get any GAI files. */ if( *status == SAI__OK ) { kpg1Rgndf( "GAI", size, size, "", &igrpg, &ngai, status ); if( *status == PAR__NULL ) { errAnnul( status ); ngai = 0; } } /* Get any instrumental polarisation files. */ if( *status == SAI__OK ) { /* First see if the user wants to use the "INSTQ/INSTU" scheme for specifying instrumental polarisation. */ ndfAssoc( "INSTQ", "Read", &indfiq, status ); ndfAssoc( "INSTU", "Read", &indfiu, status ); if( *status == PAR__NULL ) { ndfAnnul( &indfiq, status ); ndfAnnul( &indfiu, status ); errAnnul( status ); } else { msgOut( " ", "Using user-defined IP model", status ); ndfDim( indfiq, 2, dims, &ndim, status ); if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) { *status = SAI__ERROR; ndfMsg( "N", indfiq ); errRep( " ", "Instrumental polarisation file ^N has bad " "dimensions - should be 32x40.", status ); } else { ndfMap( indfiq, "DATA", "_DOUBLE", "READ", (void **) &qinst_data, &nel, status ); } ndfDim( indfiu, 2, dims, &ndim, status ); if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) { *status = SAI__ERROR; ndfMsg( "N", indfiu ); errRep( " ", "Instrumental polarisation file ^N has bad " "dimensions - should be 32x40.", status ); } else { ndfMap( indfiu, "DATA", "_DOUBLE", "READ", (void **) &uinst_data, &nel, status ); } } /* If not, see if the user wants to use the Johnstone/Kennedy instrumental polarisation model. The IPDATA parameter gives the path to an HDS container file contining NDFs holding the required IP data for all subarrays. */ if( !qinst_data ) { parGet0c( "IPDATA", ipdata, sizeof(ipdata), status ); if( *status == PAR__NULL ) { errAnnul( status ); } else { msgOutf( " ", "Using Johnstone/Kennedy IP model in %s", status, ipdata ); hdsOpen( ipdata, "READ", &iploc, status ); } } } /* Loop round all the template time series files. */ for( ifile = 1; ifile <= (int) size && *status == SAI__OK; ifile++ ) { /* Start a new NDF context. */ ndfBegin(); /* Create the output NDF by propagating everything from the input, except for quality and variance. */ ndgNdfas( igrp2, ifile, "READ", &indfin, status ); ndfMsg( "FILE", indfin ); msgSeti( "THISFILE", ifile ); msgSeti( "NUMFILES", size ); msgOutif( MSG__NORM, " ", "Simulating ^THISFILE/^NUMFILES ^FILE", status ); ndgNdfpr( indfin, "DATA,HISTORY,LABEL,TITLE,WCS,UNITS,EXTENSION(*)", ogrp, ifile, &indfout, status ); ndfAnnul( &indfin, status ); ndfAnnul( &indfout, status ); /* We now re-open the output NDF and then modify its data values. */ smf_open_file( wf, ogrp, ifile, "UPDATE", 0, &odata, status ); /* Issue a suitable message and abort if anything went wrong. */ if( *status != SAI__OK ) { errRep( FUNC_NAME, "Could not open input template file.", status ); break; } else { if( odata->file == NULL ) { *status = SAI__ERROR; errRep( FUNC_NAME, "No smfFile associated with smfData.", status ); break; } else if( odata->hdr == NULL ) { *status = SAI__ERROR; errRep( FUNC_NAME, "No smfHead associated with smfData.", status ); break; } } /* Check the reference time series contains double precision values. */ smf_dtype_check_fatal( odata, NULL, SMF__DOUBLE, status ); /* Get the total number of data elements, and the number of time slices. */ smf_get_dims( odata, NULL, NULL, NULL, &ntslice, &ndata, NULL, NULL, status ); /* Get the subarray name */ smf_fits_getS( odata->hdr, "SUBARRAY", subarray, sizeof(subarray), status ); /* If we are using the Johnstone/Kennedy IP model, open and map the relevant parameter NDFs within the IPDATA container file. */ if( iploc ) { datFind( iploc, subarray, &cloc, status ); ndfFind( cloc, "C0", &indfc0, status ); ndfDim( indfc0, 2, dims, &ndim, status ); if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) { *status = SAI__ERROR; ndfMsg( "N", indfc0 ); errRep( " ", "Instrumental polarisation file ^N has bad " "dimensions - should be 32x40.", status ); } else { ndfMap( indfc0, "DATA", "_DOUBLE", "READ", (void **) &c0_data, &nel, status ); } ndfFind( cloc, "P0", &indfp0, status ); ndfDim( indfp0, 2, dims, &ndim, status ); if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) { *status = SAI__ERROR; ndfMsg( "N", indfp0 ); errRep( " ", "Instrumental polarisation file ^N has bad " "dimensions - should be 32x40.", status ); } else { ndfMap( indfp0, "DATA", "_DOUBLE", "READ", (void **) &p0_data, &nel, status ); } ndfFind( cloc, "P1", &indfp1, status ); ndfDim( indfp1, 2, dims, &ndim, status ); if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) { *status = SAI__ERROR; ndfMsg( "N", indfp1 ); errRep( " ", "Instrumental polarisation file ^N has bad " "dimensions - should be 32x40.", status ); } else { ndfMap( indfp1, "DATA", "_DOUBLE", "READ", (void **) &p1_data, &nel, status ); } ndfFind( cloc, "ANGC", &indfangc, status ); ndfDim( indfangc, 2, dims, &ndim, status ); if( dims[ 0 ] != 32 || dims[ 1 ] != 40 ) { *status = SAI__ERROR; ndfMsg( "N", indfangc ); errRep( " ", "Instrumental polarisation file ^N has bad " "dimensions - should be 32x40.", status ); } else { ndfMap( indfangc, "DATA", "_DOUBLE", "READ", (void **) &angc_data, &nel, status ); } } /* Open any COM file. */ if( ncom ) { ndgNdfas( igrpc, ifile, "READ", &indfc, status ); ndfDim( indfc, 3, cdims, &ndimc, status ); /* Check its dimensions. */ if( *status == SAI__OK ) { if( ndimc == 1 ) { if( cdims[ 0 ] < (int) ntslice ) { *status = SAI__ERROR; ndfMsg( "C", indfc ); ndfMsg( "R", indfin ); msgSeti( "N", cdims[ 0 ] ); msgSeti( "M", ntslice ); errRep( " ", "Supplied COM file (^C) has ^N time-slices, but " "the reference NDF (^R) has ^M time-slices.", status ); } else { ndfBound( indfc, 3, lbndc, ubndc, &ndimc, status ); ubndc[ 0 ] = lbndc[ 0 ] + ntslice - 1; ndfSect( indfc, 1, lbndc, ubndc, &indfcs, status ); } } else if( ndimc == 3 ) { if( cdims[ 0 ] != 1 || cdims[ 1 ] != 1 ) { *status = SAI__ERROR; ndfMsg( "C", indfc ); errRep( " ", "Supplied 3D COM file (^C) has bad " "dimensions for axis 1 and/or 2 (should " "both be 1 pixel long).", status ); } else if( cdims[ 2 ] < (int) ntslice ) { *status = SAI__ERROR; ndfMsg( "C", indfc ); ndfMsg( "R", indfin ); msgSeti( "N", cdims[ 2 ] ); msgSeti( "M", ntslice ); errRep( " ", "Supplied COM file (^C) has ^N time-slices, but " "the reference NDF (^R) has ^M time-slices.", status ); } else { ndfBound( indfc, 3, lbndc, ubndc, &ndimc, status ); ubndc[ 2 ] = lbndc[ 2 ] + ntslice - 1; ndfSect( indfc, 3, lbndc, ubndc, &indfcs, status ); } } else { *status = SAI__ERROR; ndfMsg( "C", indfc ); msgSeti( "N", ndimc ); errRep( " ", "Supplied COM file (^C) has ^N dimensions - " "must be 3.", status ); } } ndfMap( indfcs, "DATA", "_DOUBLE", "READ", (void **) &inc_data, &nelc, status ); } else { indfcs = NDF__NOID; inc_data = NULL; } /* Open any GAI files. */ if( ngai ) { ndgNdfas( igrpg, ifile, "READ", &indfg, status ); ndfDim( indfg, 3, gdims, &ndimg, status ); /* Check its dimensions, and map it if OK. */ if( *status == SAI__OK ) { if( ndimg != 2 ) { *status = SAI__ERROR; ndfMsg( "C", indfg ); msgSeti( "N", ndimg ); errRep( " ", "Supplied GAI file (^C) has ^N dimensions - " "must be 2.", status ); } else if( gdims[ 0 ] != 32 || gdims[ 1 ] != 40 ) { *status = SAI__ERROR; ndfMsg( "C", indfg ); errRep( " ", "Supplied GAI file (^C) has has bad " "dimensions - should be 32x40.", status ); } } ndfMap( indfg, "DATA", "_DOUBLE", "READ", (void **) &gai_data, &nelg, status ); } else { indfg = NDF__NOID; gai_data = NULL; } /* Fill the output with bad values. */ if( *status == SAI__OK ) { pd = odata->pntr[ 0 ]; for( iel = 0; iel < ndata; iel++ ) *(pd++) = VAL__BADD; } /* Resample the sky map data into the output time series. */ smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd, interp, params, sigma, in_data, odata->pntr[ 0 ], NULL, &ngood, status ); /* Add on any COM data. */ smf_addcom( wf, odata, inc_data, status ); /* Issue a wrning if there is no good data in the output cube. */ if( ngood == 0 ) msgOutif( MSG__NORM, " ", " Output contains no " "good data values.", status ); /* If Q and U maps have been given, allocate room to hold resampled Q and U values, and fill them with bad values. */ if( inq_data && inu_data ) { pq = outq_data = astMalloc( ndata*sizeof( *outq_data ) ); pu = outu_data = astMalloc( ndata*sizeof( *outu_data ) ); if( *status == SAI__OK ) { for( iel = 0; iel < ndata; iel++ ) { *(pu++) = VAL__BADD; *(pq++) = VAL__BADD; } } /* Determine the harmonic to use. */ parGet0i( "HARMONIC", &harmonic, status ); /* If producing the normal 8 Hz harmonic, get the amplitude and phase of a other signals to add onto the 8 Hz signal. */ if( harmonic == 4 ) { parGet0d( "AMP2", &2, status ); parGet0d( "PHASE2", &phase2, status ); parGet0d( "AMP4", &4, status ); parGet0d( "PHASE4", &phase4, status ); parGet0d( "AMP16", &16, status ); parGet0d( "PHASE16", &phase16, status ); } else { amp2 = 0.0; phase2 = 0.0; amp4 = 0.0; phase4 = 0.0; amp16 = 0.0; phase16 = 0.0; } /* Allocate room for an array to hold the angle from the Y pixel axis in the sky map to the focal plane Y axis, in radians, at each time slice. Positive rotation is in the same sense as rotation from focal plane X to focal plane Y. */ ang_data = astMalloc( ntslice*sizeof( *ang_data ) ); /* Resample them both into 3D time series. These Q/U values arw with respect to the sky image Y axis. */ smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd, interp, params, sigma, inq_data, outq_data, ang_data, &ngood, status ); smf_resampmap( wf, odata, abskyfrm, skymap, moving, slbnd, subnd, interp, params, sigma, inu_data, outu_data, NULL, &ngood, status ); /* Combine these time series with the main output time series so that the main output is analysed intensity. */ smf_uncalc_iqu( wf, odata, odata->pntr[ 0 ], outq_data, outu_data, ang_data, pasign, AST__DD2R*paoff, AST__DD2R*angrot, amp2, AST__DD2R*phase2, amp4, AST__DD2R*phase4, amp16, AST__DD2R*phase16, qinst_data, uinst_data, c0_data, p0_data, p1_data, angc_data, harmonic, status ); /* Release work space. */ outq_data = astFree( outq_data ); outu_data = astFree( outu_data ); ang_data = astFree( ang_data ); } /* Factor in any GAI data. */ smf_addgai( wf, odata, gai_data, status ); /* Close the output time series file. */ smf_close_file( wf, &odata, status ); /* Close the IP data container for the current subarray, if it is open. */ if( cloc ) datAnnul( &cloc, status ); /* End the NDF context. */ ndfEnd( status ); } /* Close any input data file that is still open due to an early exit from the above loop. */ if( odata != NULL ) { smf_close_file( wf, &odata, status ); odata = NULL; } /* Free remaining resources. */ if( igrp1 != NULL) grpDelet( &igrp1, status); if( igrp2 != NULL) grpDelet( &igrp2, status); if( igrpq != NULL) grpDelet( &igrpq, status); if( igrpu != NULL) grpDelet( &igrpu, status); if( igrpc != NULL) grpDelet( &igrpc, status); if( igrpg != NULL) grpDelet( &igrpg, status); if( ogrp != NULL) grpDelet( &ogrp, status); if( iploc ) datAnnul( &iploc, status ); /* End the NDF context. */ ndfEnd( status ); /* End the tile's AST context. */ astEnd; /* Issue a status indication.*/ if( *status == SAI__OK ) { msgOutif(MSG__VERB," ",TASK_NAME " succeeded, time series written.", status); } else { msgOutif(MSG__VERB," ",TASK_NAME " failed.", status); } }
void smurf_sc2clean( int *status ) { smfArray *array = NULL; /* Data to be cleaned */ Grp *basegrp=NULL; /* Grp containing first file each chunk */ size_t basesize; /* Number of files in base group */ smfArray *bbms = NULL; /* Bad bolometer masks */ smfArray *concat=NULL; /* Pointer to a smfArray */ size_t contchunk; /* Continuous chunk counter */ smfArray *darks = NULL; /* Dark data */ int ensureflat; /* Flag for flatfielding data */ smfArray *flatramps = NULL;/* Flatfield ramps */ AstKeyMap *heateffmap = NULL; /* Heater efficiency data */ smfData *odata = NULL; /* Pointer to output data struct */ Grp *fgrp = NULL; /* Filtered group, no darks */ size_t gcount=0; /* Grp index counter */ size_t idx; /* Subarray counter */ Grp *igrp = NULL; /* Input group of files */ smfGroup *igroup=NULL; /* smfGroup corresponding to igrp */ dim_t maxconcat=0; /* Longest continuous chunk length in samples */ double maxlen=0; /* Constrain maxconcat to this many seconds */ size_t ncontchunks=0; /* Number continuous chunks outside iter loop */ Grp *ogrp = NULL; /* Output group of files */ size_t osize; /* Total number of NDF names in the output group */ dim_t padStart=0; /* How many samples padding at start */ dim_t padEnd=0; /* How many samples padding at end */ size_t size; /* Number of files in input group */ int temp; /* Temporary signed integer */ int usedarks; /* flag for using darks */ ThrWorkForce *wf = NULL; /* Pointer to a pool of worker threads */ int writecom; /* Write COMmon mode to NDF if calculated? */ int writegai; /* Write GAIns to NDF if calculated? */ /* Main routine */ ndfBegin(); /* Find the number of cores/processors available and create a pool of threads of the same size. */ wf = thrGetWorkforce( thrGetNThread( SMF__THREADS, status ), status ); /* Read the input file */ kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status ); /* Filter out darks */ smf_find_science( wf, igrp, &fgrp, 1, NULL, NULL, 1, 1, SMF__NULL, &darks, &flatramps, &heateffmap, NULL, status ); /* input group is now the filtered group so we can use that and free the old input group */ size = grpGrpsz( fgrp, status ); grpDelet( &igrp, status); igrp = fgrp; fgrp = NULL; if (size == 0) { msgOutif(MSG__NORM, " ","All supplied input frames were filtered," " nothing to do", status ); goto CLEANUP; } /* --- Parse ADAM parameters ---------------------------------------------- */ /* Maximum length of a continuous chunk */ parGdr0d( "MAXLEN", 0, 0, VAL__MAXD, 1, &maxlen, status ); /* Padding */ parGdr0i( "PADSTART", 0, 0, VAL__MAXI, 1, &temp, status ); padStart = (dim_t) temp; parGdr0i( "PADEND", 0, 0, VAL__MAXI, 1, &temp, status ); padEnd = (dim_t) temp; /* Are we using darks? */ parGet0l( "USEDARKS", &usedarks, status ); /* Are we flatfielding? */ parGet0l( "FLAT", &ensureflat, status ); /* Write COM/GAI to NDFs if calculated? */ parGet0l( "COM", &writecom, status ); parGet0l( "GAI", &writegai, status ); /* Get group of bolometer masks and read them into a smfArray */ smf_request_mask( wf, "BBM", &bbms, status ); /* Group the input files by subarray and continuity ----------------------- */ smf_grp_related( igrp, size, 1, 0, maxlen-padStart-padEnd, NULL, NULL, &maxconcat, NULL, &igroup, &basegrp, NULL, status ); /* Obtain the number of continuous chunks and subarrays */ if( *status == SAI__OK ) { ncontchunks = igroup->chunk[igroup->ngroups-1]+1; } basesize = grpGrpsz( basegrp, status ); /* Get output file(s) */ kpg1Wgndf( "OUT", basegrp, basesize, basesize, "More output files required...", &ogrp, &osize, status ); /* Loop over continuous chunks and clean -----------------------------------*/ gcount = 1; for( contchunk=0;(*status==SAI__OK)&&contchunk<ncontchunks; contchunk++ ) { AstKeyMap *keymap=NULL; int dkclean; AstKeyMap *sub_instruments=NULL; /* Place cleaning parameters into a keymap and set defaults. Do this inside the loop in case we are cleaning files with differing sub-instruments. Note that we use the map-maker defaults file here (which loads the sc2clean defaults) so that we populate the locked keymap with all the parameters that people may come across to allow them to load their map-maker config directly into sc2clean. */ sub_instruments = smf_subinst_keymap( SMF__SUBINST_NONE, NULL, igrp, igroup->subgroups[contchunk][0], status ); keymap = kpg1Config( "CONFIG", "$SMURF_DIR/smurf_makemap.def", sub_instruments, 1, status ); if( sub_instruments ) sub_instruments = astAnnul( sub_instruments ); /* Now rerun smf_grp_related to figure out how long each downsampled chunk of data will be. */ if( basegrp ) grpDelet( &basegrp, status ); if( igroup ) smf_close_smfGroup( &igroup, status ); smf_grp_related( igrp, size, 1, 0, maxlen-padStart-padEnd, NULL, keymap, &maxconcat, NULL, &igroup, &basegrp, NULL, status ); /* Concatenate this continuous chunk */ smf_concat_smfGroup( wf, NULL, igroup, usedarks ? darks:NULL, bbms, flatramps, heateffmap, contchunk, ensureflat, 1, NULL, 0, NULL, NULL, NO_FTS, padStart, padEnd, 0, &concat, NULL, status ); if( *status == SAI__OK) { /* clean the dark squids now since we might need to use them to clean the bolometer data */ smf_get_cleanpar( keymap, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dkclean, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, status ); for( idx=0; dkclean&&(*status==SAI__OK)&&idx<concat->ndat; idx++ ) { odata = concat->sdata[idx]; if( odata && odata->da && odata->da->dksquid ) { smfData *dksquid = odata->da->dksquid; AstKeyMap *kmap=NULL; msgOut("", TASK_NAME ": cleaning dark squids", status); /* fudge the header so that we can get at JCMTState */ dksquid->hdr = odata->hdr; /* clean darks using cleandk.* parameters */ astMapGet0A( keymap, "CLEANDK", &kmap ); array = smf_create_smfArray( status ); smf_addto_smfArray( array, dksquid, status ); smf_clean_smfArray( wf, array, NULL, NULL, NULL, kmap, status ); if( array ) { array->owndata = 0; smf_close_related( wf, &array, status ); } if( kmap ) kmap = astAnnul( kmap ); /* Unset hdr pointer so that we don't accidentally close it */ dksquid->hdr = NULL; } } /* Then the main data arrays */ if( *status == SAI__OK ) { smfArray *com = NULL; smfArray *gai = NULL; char filename[GRP__SZNAM+1]; msgOut("", TASK_NAME ": cleaning bolometer data", status ); smf_clean_smfArray( wf, concat, NULL, &com, &gai, keymap, status ); /* If ADAM parameters for COM or GAI were specified, and the common-mode was calculated, export to files here */ if( writecom && com ) { for( idx=0; (*status==SAI__OK)&&(idx<com->ndat); idx++ ) { smf_model_createHdr( com->sdata[idx], SMF__COM, concat->sdata[idx], status ); smf_stripsuffix( com->sdata[idx]->file->name, SMF__DIMM_SUFFIX, filename, status ); smf_dataOrder( wf, com->sdata[idx], 1, status ); smf_write_smfData( wf, com->sdata[idx], NULL, filename, NULL, 0, NDF__NOID, MSG__NORM, 0, NULL, NULL, status ); } } if( writegai && gai ) { for( idx=0; (*status==SAI__OK)&&(idx<gai->ndat); idx++ ) { smf_model_createHdr( gai->sdata[idx], SMF__GAI, concat->sdata[idx], status ); smf_stripsuffix( gai->sdata[idx]->file->name, SMF__DIMM_SUFFIX, filename, status ); smf_dataOrder( wf, gai->sdata[idx], 1, status ); smf_write_smfData( wf, gai->sdata[idx], NULL, filename, NULL, 0, NDF__NOID, MSG__NORM, 0, NULL, NULL, status ); } } /* Close com and gai */ if( com ) smf_close_related( wf, &com, status ); if( gai ) smf_close_related( wf, &gai, status ); } /* Report statistics (currently need a smfArray for that) */ if (*status == SAI__OK) { size_t last_qcount[SMF__NQBITS]; size_t last_nmap = 0; smf_qualstats_report( wf, MSG__VERB, SMF__QFAM_TSERIES, 1, concat, last_qcount, &last_nmap, 1, NULL, NULL, status ); } /* Clean up for contchunk loop */ if( keymap ) keymap = astAnnul( keymap ); } /* Export concatenated/cleaned data for each subarray to NDF file */ for( idx=0; (*status==SAI__OK)&&idx<concat->ndat; idx++ ) { odata = concat->sdata[idx]; /* Complete the history information in the output NDF so that it includes group parameters accessed since the default history information was written to the NDF (in smf_open_and_flatfield). */ smf_puthistory( odata, "SMURF:SC2CLEAN", status ); /* Ensure ICD data order */ smf_dataOrder( wf, odata, 1, status ); if( odata->file && odata->file->name ) { smf_write_smfData( wf, odata, NULL, NULL, ogrp, gcount, NDF__NOID, MSG__VERB, 0, NULL, NULL, status ); } else { *status = SAI__ERROR; errRep( FUNC_NAME, "Unable to determine file name for concatenated data.", status ); } /* Increment the group index counter */ gcount++; } /* Close the smfArray */ smf_close_related( wf, &concat, status ); } /* Write out the list of output NDF names, annulling the error if a null parameter value is supplied. */ if( *status == SAI__OK && ogrp ) { grpList( "OUTFILES", 0, 0, NULL, ogrp, status ); if( *status == PAR__NULL ) errAnnul( status ); } CLEANUP: /* Tidy up after ourselves: release the resources used by the grp routines */ if( darks ) smf_close_related( wf, &darks, status ); if( flatramps ) smf_close_related( wf, &flatramps, status ); if (heateffmap) heateffmap = smf_free_effmap( heateffmap, status ); if( bbms ) smf_close_related( wf, &bbms, status ); if( igrp ) grpDelet( &igrp, status); if( ogrp ) grpDelet( &ogrp, status); if( basegrp ) grpDelet( &basegrp, status ); if( igroup ) smf_close_smfGroup( &igroup, status ); fftw_cleanup(); ndfEnd( status ); }
void smurf_jsatilelist( int *status ) { /* Local Variables */ AstFitsChan *fc = NULL; AstFrameSet *fs = NULL; AstObject *obj; AstRegion *region; Grp *igrp = NULL; Grp *sgrp = NULL; double vertex_data[ 2*MAXVERT ]; int *tiles = NULL; int i; int indf; int lbnd[2]; int ntile; int nvert_dec; int nvert_ra; int ubnd[2]; size_t size; size_t ssize; smfJSATiling tiling; /* Check inherited status */ if( *status != SAI__OK ) return; /* Start a new AST context. */ astBegin; /* Attempt to to get an AST Region. */ kpg1Gtobj( "IN", "Region", (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion), &obj, status ); region = (AstRegion *) obj; /* If successful, attempt to access the IN parameter as an NDF. If this works, we may be able to determine the instrument by looking at its FITS extension. */ if( *status == SAI__OK && region ) { ndfExist( "IN", "Read", &indf, status ); /* If we got an NDF, get a FitsChan holding the contents of its FITS extension. Annul the error if the NDF has no FITS extension. */ if( indf != NDF__NOID ) { kpgGtfts( indf, &fc, status ); if( *status == KPG__NOFTS ) { errAnnul( status ); fc = NULL; } ndfAnnul( &indf, status ); } /* Select a JSA instrument and get the parameters defining the layout of tiles for the selected instrument. */ smf_jsainstrument( "INSTRUMENT", fc, SMF__INST_NONE, &tiling, status ); /* Get the list of identifiers for tiles that overlap the region. */ tiles = smf_jsatiles_region( region, &tiling, &ntile, status ); /* If a null value was supplied for IN, attempt to get the positions of vertices on the sky to define the region. */ } else if( *status == PAR__NULL ) { errAnnul( status ); parGet1d( "VERTEX_RA", MAXVERT, vertex_data, &nvert_ra, status ); parGet1d( "VERTEX_DEC", MAXVERT, vertex_data + MAXVERT, &nvert_dec, status ); if( nvert_ra != nvert_dec && *status == SAI__OK ) { *status = SAI__ERROR; errRepf( "", "Differing numbers of RA (%d) and Dec (%d) vertex values " "supplied.", status, nvert_ra, nvert_dec ); } /* Convert from degrees to radians. */ for( i = 0; i < nvert_ra; i++ ) { vertex_data[ i ] *= AST__DD2R; vertex_data[ MAXVERT + i ] *= AST__DD2R; } /* Select a JSA instrument and get the parameters defining the layout of tiles for the selected instrument. */ smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &tiling, status ); /* Create a frame in which to define the region - we arbitrarily use tile 1. */ smf_jsatile( 1, &tiling, 0, NULL, &fs, NULL, lbnd, ubnd, status ); /* Create the region. */ region = (AstRegion *) astPolygon( fs, nvert_ra, MAXVERT, vertex_data, NULL, " " ); /* If the region is unbounded, it is probably because the vertices were given in the wrong order. Invert the Polyfon to correct this. */ if( !astGetI( region, "bounded" ) ) astNegate( region ); /* Get the list of identifiers for tiles that overlap the region. */ tiles = smf_jsatiles_region( region, &tiling, &ntile, status ); } /* If the IN parameter could not be accessed as a Region, annull any error and get a group of input data files. */ if( !region || *status == SAI__ERROR ) { if( *status != SAI__OK ) errAnnul( status ); kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status ); /* Get a group containing just the files holding science data. */ smf_find_science( NULL, igrp, &sgrp, 0, NULL, NULL, 1, 1, SMF__NULL, NULL, NULL, NULL, NULL, status ); /* Check we have at least once science file. */ ssize = grpGrpsz( sgrp, status ); if( ssize == 0 ) { msgOutif( MSG__NORM, " ", "None of the supplied input frames were SCIENCE.", status ); /* Get the list of identifiers for tiles that receive any data. */ } else { tiles = smf_jsatiles_data( sgrp, ssize, &tiling, &ntile, status ); } /* Delete the groups. */ if( igrp ) grpDelet( &igrp, status); if( sgrp ) grpDelet( &sgrp, status); } /* Sort the list of overlapping tiles into ascending order. */ if( *status == SAI__OK ) { qsort( tiles, ntile, sizeof( *tiles ), jsatilelist_icomp ); /* Display the list of overlapping tiles. */ msgBlank( status ); msgOutf( "", " %s tiles touched by supplied data:", status, tiling.name ); msgBlank( status ); for( i = 0; i < ntile; i++ ) { msgSeti( "I", tiles[ i ] ); msgOut( "", " ^I", status ); } msgBlank( status ); /* Write out the list of overlapping tiles to the output parameter. */ parPut1i( "TILES", ntile, tiles, status ); } /* Free resources. */ tiles = astFree( tiles ); /* End the AST context. */ astEnd; /* Issue a status indication.*/ msgBlank( status ); if( *status == SAI__OK ) { msgOutif( MSG__VERB, "", "JSATILELIST succeeded.", status); } else { msgOutif( MSG__VERB, "", "JSATILELIST failed.", status); } }