int CplxDumpGadget::
 process(GadgetContainerMessage<ISMRMRD::AcquisitionHeader>* m1,
         GadgetContainerMessage< hoNDArray< std::complex<float> > >* m2)
 {
   
   // Noise should have been consumed by the noise adjust, but just in case...
   //
   
   bool is_noise = ISMRMRD::FlagBit(ISMRMRD::ISMRMRD_ACQ_IS_NOISE_MEASUREMENT).isSet(m1->getObjectPtr()->flags);
   if (is_noise) {
     m1->release();
     return GADGET_OK;
   }
   
   GadgetContainerMessage< hoNDArray< std::complex<float> > >* copy = new GadgetContainerMessage< hoNDArray< std::complex<float> > >;
   *copy->getObjectPtr() = *m2->getObjectPtr();
   
   if (buffer_.enqueue_tail(copy) < 0) {
     GDEBUG("Failed to add profile to buffer\n");
     copy->release();
     return GADGET_FAIL;
   }
   
   if (this->next()->putq(m1) < 0) {
     GDEBUG("Unable to put data on queue\n");
     return GADGET_FAIL;
   }
   
   return GADGET_OK;
 }
Пример #2
0
 template<class T> GadgetContainerMessage< hoNDArray<T> >*
 NFFT2DGadget::duplicate_array( GadgetContainerMessage< hoNDArray<T> > *array )
 {
   GadgetContainerMessage< hoNDArray<T> > *copy = new GadgetContainerMessage< hoNDArray<T> >();   
   *(copy->getObjectPtr()) = *(array->getObjectPtr());
   return copy;
 }
Пример #3
0
  boost::shared_ptr< hoNDArray<float_complext> > 
  NFFT2DGadget::extract_samples_from_queue ( ACE_Message_Queue<ACE_MT_SYNCH> *queue )                                             
  {    
    if(!queue) {
      GDEBUG("Illegal queue pointer, cannot extract samples\n");
      throw std::runtime_error("NFFT2DGadget::extract_samples_from_queue: illegal queue pointer");	
    }

    unsigned int readouts_buffered = queue->message_count();
    
    std::vector<size_t> dims;
    dims.push_back(samples_per_readout_*readouts_buffered);
    dims.push_back(num_coils_);
    
    boost::shared_ptr< hoNDArray<float_complext> > host_samples(new hoNDArray<float_complext>(dims));
    
    for (unsigned int p=0; p<readouts_buffered; p++) {
      
      ACE_Message_Block* mbq;
      if (queue->dequeue_head(mbq) < 0) {
        GDEBUG("Message dequeue failed\n");
        throw std::runtime_error("NFFT2DGadget::extract_samples_from_queue: dequeing failed");	
      }
      
      GadgetContainerMessage< hoNDArray< std::complex<float> > > *daq = AsContainerMessage<hoNDArray< std::complex<float> > >(mbq);
	
      if (!daq) {
        GDEBUG("Unable to interpret data on message queue\n");
        throw std::runtime_error("NFFT2DGadget::extract_samples_from_queue: failed to interpret data");	
      }
	
      for (unsigned int c = 0; c < num_coils_; c++) {
	
        float_complext *data_ptr = host_samples->get_data_ptr();
        data_ptr += c*samples_per_readout_*readouts_buffered+p*samples_per_readout_;
	    
        std::complex<float> *r_ptr = daq->getObjectPtr()->get_data_ptr();
        r_ptr += c*daq->getObjectPtr()->get_size(0);
	  
        memcpy(data_ptr, r_ptr, samples_per_readout_*sizeof(float_complext));
      }

      mbq->release();
    }
    
    return host_samples;
  }
Пример #4
0
  boost::shared_ptr< hoNDArray<float> > 
  NFFT2DGadget::extract_trajectory_from_queue ( ACE_Message_Queue<ACE_MT_SYNCH> *queue )
  {    
    if(!queue) {
      GDEBUG("Illegal queue pointer, cannot extract trajectory\n");
      throw std::runtime_error("NFFT2DGadget::extract_trajectory_from_queue: illegal queue pointer");	
    }

    unsigned int readouts_buffered = queue->message_count();
    
    std::vector<size_t> dims;
    dims.push_back(num_trajectory_dims_); // 2 for trajectories only, 3 for both trajectories + dcw
    dims.push_back(samples_per_readout_);
    dims.push_back(readouts_buffered);
    
    boost::shared_ptr< hoNDArray<float> > host_traj(new hoNDArray<float>(&dims));
    
    for (unsigned int p=0; p<readouts_buffered; p++) {      
      ACE_Message_Block* mbq;
      if (queue->dequeue_head(mbq) < 0) {
        GDEBUG("Message dequeue failed\n");
        throw std::runtime_error("NFFT2DGadget::extract_trajectory_from_queue: dequeing failed");	
      }
      
      GadgetContainerMessage< hoNDArray<float> > *daq = AsContainerMessage<hoNDArray<float> >(mbq);
	
      if (!daq) {
        GDEBUG("Unable to interpret data on message queue\n");
        throw std::runtime_error("NFFT2DGadget::extract_trajectory_from_queue: failed to interpret data");	
      }

      float *data_ptr = host_traj->get_data_ptr();
      data_ptr += num_trajectory_dims_*samples_per_readout_*p;
      
      float *r_ptr = daq->getObjectPtr()->get_data_ptr();
      
      memcpy(data_ptr, r_ptr, num_trajectory_dims_*samples_per_readout_*sizeof(float));
      
      mbq->release();
    }
    
    return host_traj;
  }
Пример #5
0
bool GtPlusReconJob2DTGadget::
sendOutJob(int jobID, GtPlusReconJobTypeCPFL* job)
{
    try
    {
      GDEBUG("GtPlusReconJob2DTGadget sendOutJob ...\n");

        if (!this->controller_)
        {
	  GERROR("Cannot return result to controller, no controller set\n");
	  return false;
        }

        GadgetContainerMessage<GadgetMessageIdentifier>* mb =
            new GadgetContainerMessage<GadgetMessageIdentifier>();

        mb->getObjectPtr()->id = GADGET_MESSAGE_CLOUD_JOB;

        GadgetContainerMessage<int>* m1 = new GadgetContainerMessage<int>();
        *(m1->getObjectPtr()) = jobID;

        GadgetContainerMessage<GtPlusReconJobTypeCPFL>* m2 = new GadgetContainerMessage<GtPlusReconJobTypeCPFL>();

        *(m2->getObjectPtr()) = *job;

        m1->cont(m2);
        mb->cont(m1);

        int ret =  this->controller_->output_ready(mb);
        if (ret < 0)
        {
            GDEBUG("Failed to return GtPlusReconJob2DTGadget job massage to controller\n");
            return false;
        }
    }
    catch(...)
    {
        GERROR_STREAM("Errors in GtPlusReconJob2DTGadget::sendOutJob(...) ... ");
        return false;
    }

    return true;
}
    int ImageFinishGadget::process(GadgetContainerMessage<ISMRMRD::ImageHeader>* m1)
    {
        if (!this->controller_)
        {
            GERROR("Cannot return result to controller, no controller set");
            return -1;
        }

        GadgetContainerMessage<GadgetMessageIdentifier>* mb = new GadgetContainerMessage<GadgetMessageIdentifier>();

        mb->getObjectPtr()->id = GADGET_MESSAGE_ISMRMRD_IMAGE;
        mb->cont(m1);

        int ret = this->controller_->output_ready(mb);

        if ((ret < 0))
        {
            GERROR("Failed to return massage to controller\n");
            return GADGET_FAIL;
        }

        return GADGET_OK;
    }
  int SpiralToGenericGadget::
  process(GadgetContainerMessage<ISMRMRD::AcquisitionHeader> *m1,
	  GadgetContainerMessage< hoNDArray< std::complex<float> > > *m2)
  {
    // Noise should have been consumed by the noise adjust, but just in case...
    //

    bool is_noise = m1->getObjectPtr()->isFlagSet(ISMRMRD::ISMRMRD_ACQ_IS_NOISE_MEASUREMENT);
    if (is_noise) {
      m1->release();
      return GADGET_OK;
    }

    // Delete previously attached trajectories 
    if (m2->cont()) {
	    m2->cont()->release();
    }
    
    // Compute hoNDArray of trajectory and weights at first pass
    //

    if (!prepared_) {

      int     nfov   = 1;         /*  number of fov coefficients.             */
      int     ngmax  = 1e5;       /*  maximum number of gradient samples      */
      double  *xgrad;             /*  x-component of gradient.                */
      double  *ygrad;             /*  y-component of gradient.                */
      double  *x_trajectory;
      double  *y_trajectory;
      double  *weighting;
      int     ngrad;
      double sample_time = (1.0*Tsamp_ns_) * 1e-9;

      // Calculate gradients 
      calc_vds(smax_,gmax_,sample_time,sample_time,Nints_,&fov_,nfov,krmax_,ngmax,&xgrad,&ygrad,&ngrad);

      samples_per_interleave_ = std::min(ngrad,static_cast<int>(m1->getObjectPtr()->number_of_samples));
      GDEBUG("Using %d samples per interleave\n", samples_per_interleave_);

      // Calculate the trajectory and weights
      calc_traj(xgrad, ygrad, samples_per_interleave_, Nints_, sample_time, krmax_, &x_trajectory, &y_trajectory, &weighting);

      std::vector<size_t> trajectory_dimensions;
      trajectory_dimensions.push_back(3);
      trajectory_dimensions.push_back(samples_per_interleave_*Nints_);

      host_traj_ = boost::shared_ptr< hoNDArray<float> >(new hoNDArray<float>(&trajectory_dimensions));

      {
	float* co_ptr = reinterpret_cast<float*>(host_traj_->get_data_ptr());
	
	for (int i = 0; i < (samples_per_interleave_*Nints_); i++) {
		co_ptr[i*3+0] = -x_trajectory[i]/2;
		co_ptr[i*3+1] = -y_trajectory[i]/2;
		co_ptr[i*3+2] = weighting[i];
	}
      }

      delete [] xgrad;
      delete [] ygrad;
      delete [] x_trajectory;
      delete [] y_trajectory;
      delete [] weighting;

      prepared_ = true;
    }

    // Adjustments based in the incoming data
    //

    if (samples_to_skip_end_ == -1) {
      samples_to_skip_end_ = m1->getObjectPtr()->number_of_samples-samples_per_interleave_;
      GDEBUG("Adjusting samples_to_skip_end_ = %d\n", samples_to_skip_end_);
    }

    // Define some utility variables
    //

    unsigned int samples_to_copy = m1->getObjectPtr()->number_of_samples-samples_to_skip_end_;
    unsigned int interleave = m1->getObjectPtr()->idx.kspace_encode_step_1;

    // Prepare for a new array continuation for the trajectory/weights of the incoming profile
    //

    std::vector<size_t> trajectory_dimensions;
    trajectory_dimensions.push_back(3);
    trajectory_dimensions.push_back(samples_per_interleave_);
    
    hoNDArray<float> *traj_source = new hoNDArray<float>
      (&trajectory_dimensions, host_traj_->get_data_ptr()+3*samples_per_interleave_*interleave);
    
    // Make a new array as continuation of m1, and pass along
    //

    GadgetContainerMessage< hoNDArray<float> > *cont = new GadgetContainerMessage< hoNDArray<float> >();
    *(cont->getObjectPtr()) = *traj_source;
    m2->cont(cont);

    //We need to make sure that the trajectory dimensions are attached. 
    m1->getObjectPtr()->trajectory_dimensions = 3;
    
    if (this->next()->putq(m1) < 0) {
      GDEBUG("Failed to put job on queue.\n");
      return GADGET_FAIL;
    }
    
    return GADGET_OK;
  }
Пример #8
0
int GadgetStreamController::svc(void)
{
  while (true) {
    GadgetMessageIdentifier id;
    ssize_t recv_cnt = 0;
    if ((recv_cnt = peer().recv_n (&id, sizeof(GadgetMessageIdentifier))) <= 0) {
      GERROR("GadgetStreamController, unable to read message identifier\n");
      return -1;
    }

    if (id.id == GADGET_MESSAGE_CLOSE) {
      stream_.close(1); //Shutdown gadgets and wait for them
      GDEBUG("Stream closed\n");
      GDEBUG("Closing writer task\n");
      this->writer_task_.close(1);
      GDEBUG("Writer task closed\n");
      continue;
    }

    GadgetMessageReader* r = readers_.find(id.id);

    if (!r) {
      GERROR("Unrecognized Message ID received: %d\n", id.id);
      return GADGET_FAIL;
    }

    ACE_Message_Block* mb = r->read(&peer());

    if (!mb) {
      GERROR("GadgetMessageReader returned null pointer\n");
      return GADGET_FAIL;
    }

    //We need to handle some special cases to make sure that we can get a stream set up.
    if (id.id == GADGET_MESSAGE_CONFIG_FILE) {
      GadgetContainerMessage<GadgetMessageConfigurationFile>* cfgm =
	AsContainerMessage<GadgetMessageConfigurationFile>(mb);

      if (!cfgm) {
	GERROR("Failed to cast message block to configuration file\n");
	mb->release();
	return GADGET_FAIL;
      } else {
	if (this->configure_from_file(std::string(cfgm->getObjectPtr()->configuration_file)) != GADGET_OK) {
	  GERROR("GadgetStream configuration failed\n");
	  mb->release();
	  return GADGET_FAIL;
	} else {
	  mb->release();
	  continue;
	}
      }
    } else if (id.id == GADGET_MESSAGE_CONFIG_SCRIPT) {
      std::string xml_config(mb->rd_ptr(), mb->length());
      if (this->configure(xml_config) != GADGET_OK) {
	GERROR("GadgetStream configuration failed\n");
	mb->release();
	return GADGET_FAIL;
      } else {
	mb->release();
	continue;
      }
    }

    ACE_Time_Value wait = ACE_OS::gettimeofday() + ACE_Time_Value(0,10000); //10ms from now
    if (stream_.put(mb) == -1) {
      GERROR("Failed to put stuff on stream, too long wait, %d\n",  ACE_OS::last_error () ==  EWOULDBLOCK);
      mb->release();
      return GADGET_FAIL;
    }
  }
  return GADGET_OK;
}
Пример #9
0
int AddMetaData::process(GadgetContainerMessage<DcmFileFormat> * m1)
{

	DcmFileFormat * dcm = m1->getObjectPtr();

	GadgetContainerMessage<std::string> * f;
	GadgetContainerMessage<ISMRMRD::MetaContainer>* meta;

	if(dcm)
	{	
		f=AsContainerMessage<std::string>(m1->cont());
	}
	else
	{	GERROR("No filename set for DICOM file\n");
		return GADGET_FAIL;
	}
	
	if(f)
	{	
		meta= AsContainerMessage<ISMRMRD::MetaContainer>(f->cont());
	}
	else
	{	
		GERROR("No meta data found for DICOM\n");
		return GADGET_FAIL;
	}

	unsigned int BUFSIZE = 1024;
        char *buf = new char[BUFSIZE];
	const char* checkbuf;
	OFCondition status;
	DcmTagKey key;
	DcmDataset *dataset = dcm->getDataset();

	float rescaleIntercept;//=	meta->getObjectPtr()->as_double(GADGETRON_IMAGE_SCALE_OFFSET);
	float rescaleSlope;//=	meta->getObjectPtr()->as_double(GADGETRON_IMAGE_SCALE_RATIO);


	static bool studyUIDmade=false;
	std::time_t rawtime;
         std::time(&rawtime);
         std::tm *timeinfo = std::localtime(&rawtime);

	if(meta->getObjectPtr()->exists("GADGETRON_IMAGE_SCALE_OFFSET") && meta->getObjectPtr()->exists("GADGETRON_IMAGE_SCALE_RATIO"))
	{
		rescaleIntercept=meta->getObjectPtr()->as_double(GADGETRON_IMAGE_SCALE_OFFSET);
		rescaleIntercept=meta->getObjectPtr()->as_double(GADGETRON_IMAGE_SCALE_OFFSET);
	


	 // Window Center
        key.set(0x0028, 0x1050);
        dataset->remove(key);
        
        // Window Width
        key.set(0x0028, 0x1051);
        dataset->remove(key);

	
	

	rescaleIntercept = -1.0*rescaleIntercept*rescaleSlope;
	
	rescaleSlope= 1.0/rescaleSlope;
	
	key.set(0x0028,0x1052);
	ACE_OS::snprintf(buf, BUFSIZE, "%f", rescaleIntercept);//
	WRITE_DCM_STRING(key, buf);

	key.set(0x0028,0x1053);
	ACE_OS::snprintf(buf, BUFSIZE, "%f", rescaleSlope);//meta->getObjectPtr()->as_double("Intercept"));
	WRITE_DCM_STRING(key, buf);


	key.set(0x0028, 0x0030);
        ACE_OS::snprintf(buf, BUFSIZE, "%.6f\\%.6f", pixel_spacing_Y, pixel_spacing_X);
	WRITE_DCM_STRING(key, buf);
	}


	key.set(0x0008,0x1030); //Study Description
	
	dataset->findAndGetString(key, checkbuf, false);
	if(checkbuf==NULL || !strcmp(checkbuf, "XXXXXXXX"))
	{
		ACE_OS::snprintf(buf, BUFSIZE, "%s", "Gadgetron^IEV");
		WRITE_DCM_STRING(key, buf);
	}


	key.set(0x0008,0x103E); //Series Description
	//if(!dataset->tagExistsWithValue(key))
	//{
		std::string type;
		
		if(meta)
			type=meta->getObjectPtr()->as_str(GADGETRON_DATA_ROLE);
		else
			type="MRI Images";
	
		ACE_OS::snprintf(buf, BUFSIZE, "%s", type.c_str());
		WRITE_DCM_STRING(key, buf);
	//}

	 
	key.set(0x0020,0x0010);//Study ID
	dataset->findAndGetString(key, checkbuf, false);
	if(checkbuf==NULL || !strcmp(checkbuf, "XXXXXXXX"))
	{
		
			WRITE_DCM_STRING(key, "1");
		
		// be sure to use the same one for all series you generate
	}
	
	//Study UID should be created in IEVChannelSumGadget. 
	key.set(0x0020,0x000D);//Study UID
	dataset->findAndGetString(key, checkbuf, false);
	if(checkbuf==NULL || !strcmp(checkbuf, "XXXXXXXX"))
	{
		
			WRITE_DCM_STRING(key, meta->getObjectPtr()->as_str("StudyInstanceUID"));
		
		// be sure to use the same one for all series you generate
	}

	std::strftime(buf, 100, "%Y%m%d", timeinfo);

	key.set(0x0008,0x0020);//Study Date
	dataset->findAndGetString(key, checkbuf, false);
	if(checkbuf==NULL || !strcmp(checkbuf, "19000101"))
	{
		WRITE_DCM_STRING(key, buf);
	}
	
	key.set(0x0008,0x0030);//Study Time
	dataset->findAndGetString(key, checkbuf, false);
	if(checkbuf==NULL || !strcmp(checkbuf, "121212"))
	{
		WRITE_DCM_STRING(key, buf);
	}
	
	key.set(0x0008,0x0021);//Series Date
	if(!dataset->tagExistsWithValue(key))
	{
		WRITE_DCM_STRING(key, buf);
	}

	key.set(0x0008,0x0012);//Instance Creation Date		
	if(!dataset->tagExistsWithValue(key))
	{
		WRITE_DCM_STRING(key, buf);
	}	
	std::strftime(buf, 100, "%H%M%S", timeinfo);



	key.set(0x0008,0x0031);//Series Time
	if(!dataset->tagExistsWithValue(key))
	{
		WRITE_DCM_STRING(key, buf);
	}	


	key.set(0x0008,0x0013);//Instance Creation Time
	if(!dataset->tagExistsWithValue(key))
	{
		WRITE_DCM_STRING(key, buf);
	}	

	key.set(0x0018,0x0081);//Echo Time

	WRITE_DCM_STRING(key, meta->getObjectPtr()->as_str("TE"));



	delete[] buf;

	
	//add try catch 

	if(-1==this->next()->putq(m1))
	{
		m1->release();
		GERROR("Unable to pass on message\n");
		return GADGET_FAIL;
	}
	return GADGET_OK;
}
Пример #10
0
  int CplxDumpGadget::close(unsigned long flags) {
    
    GDEBUG("CplxDumpGadget::close...\n");
    GDEBUG("Number of items on Q: %d\n", buffer_.message_count());

    int ret = Gadget::close(flags);
    unsigned int readouts_buffered = buffer_.message_count();

    if( readouts_buffered == 0 )
      return GADGET_OK;
    
    // Get the array size from the dimensions of the first buffer entry
    //

    ACE_Message_Block* mbq;
    if (buffer_.dequeue_head(mbq) < 0) {
      GDEBUG("Message dequeue failed\n");
      return GADGET_FAIL;
    }

    GadgetContainerMessage< hoNDArray< std::complex<float> > > *daq = AsContainerMessage<hoNDArray< std::complex<float> > >(mbq);
    
    if (!daq) {
      GDEBUG("Unable to interpret data on message queue\n");
      return GADGET_FAIL;
    }

    hoNDArray< std::complex<float> > *entry = daq->getObjectPtr();
    std::vector<size_t> dims_profile = *entry->get_dimensions();
    std::vector<size_t> dims = dims_profile;
    dims.push_back(readouts_buffered);

    // Allocate array for result
    //

    hoNDArray< std::complex<float> > result( &dims );

    // And copy over the first profile
    //

    {
      hoNDArray< std::complex<float> > tmp( &dims_profile, result.get_data_ptr() );
      tmp = *entry;
    }

    mbq->release();
    
    // Copy the remaining profiles to the array
    //
    
    for (unsigned int i = 1; i < readouts_buffered; i++) {
      
      if (buffer_.dequeue_head(mbq) < 0) {
        GDEBUG("Message dequeue failed\n");
        return GADGET_FAIL;
      }
      
      daq = AsContainerMessage<hoNDArray< std::complex<float> > >(mbq);
      
      if (!daq) {
        GDEBUG("Unable to interpret data on message queue\n");
        return GADGET_FAIL;
      }
      
      entry = daq->getObjectPtr();
      hoNDArray< std::complex<float> > tmp( &dims_profile, result.get_data_ptr()+i*entry->get_number_of_elements() );
      tmp = *entry;
      mbq->release();
    }      
  
    // Reshape to get the coil dimension as the last
    //
  
    std::vector<size_t> order; order.push_back(0); order.push_back(2); order.push_back(1);
    result = *permute( &result, &order);

    // Write out the result
    //
  
    write_nd_array< std::complex<float> >( &result, filename_.c_str() );
  
    return GADGET_OK;
  }
Пример #11
0
int IEVChannelSumGadget::process(GadgetContainerMessage< ISMRMRD::ImageHeader>* m1)
{
	GadgetContainerMessage<hoNDArray< float > > *unfiltered_unwrapped_msg_ptr =     AsContainerMessage<hoNDArray<float>>(m1->cont());

	GadgetContainerMessage<hoNDArray< float > > *filtered_unwrapped_msg_ptr =   AsContainerMessage<hoNDArray<float>>(unfiltered_unwrapped_msg_ptr->cont());
	GadgetContainerMessage<ISMRMRD::MetaContainer> *meta;
	
	static int c=0;	
	int e;
	int echo = m1->getObjectPtr()->contrast;
	float inv_echo_time;

	int echo_offset=yres*xres*num_ch*echo;

	if(!filtered_unwrapped_msg_ptr || !unfiltered_unwrapped_msg_ptr)
	{
		GERROR("Wrong types received in IEVChannelSumGadget. Filtered and unfiltered phase expected.\n");
		return GADGET_FAIL;
	}
	
	 meta = AsContainerMessage<ISMRMRD::MetaContainer>(filtered_unwrapped_msg_ptr->cont());
	
	//float* filtered_phase_ptr= filtered_unwrapped_msg_ptr->getObjectPtr()->get_data_ptr();
	
	m1->getObjectPtr()->channels=1; //yes?
	inv_echo_time=1/echoTimes[echo];//to avoid millions of divisions per slice

	memcpy(filtered_phase_ptr+echo_offset, filtered_unwrapped_msg_ptr->getObjectPtr()->get_data_ptr(), xres*yres*num_ch*sizeof(float));
	
	for (int i = 0; i < xres*yres*num_ch; i++) 

		freq_ptr[echo_offset+i] = filtered_phase_ptr[echo_offset+i]*inv_echo_time;

	hdr_ptr[echo]=*(m1->getObjectPtr());
	
	if(meta)
	{
		meta->getObjectPtr()->append("StudyInstanceUID", studyInstanceUID.c_str());//may be in xml header, may not be, in that case put it in xml so it can get to dicom
		char TE[10];
		sprintf(TE, "%f", echoTimes[echo]*1000);
		meta->getObjectPtr()->append("TE", TE);

		attributes[echo]=*(meta->getObjectPtr());
	}
	unfiltered_unwrapped_msg_ptr->release();//all data have been copied
	if(echo==(numEchos-1))
	{	
		
		float* weights= new float[xres*yres*num_ch];
		float** channel_weights= new float* [num_ch];
		float* to_normalize = new float[xres*yres];
		int ch;
		
		if(iev.value()==int(IEV::YES))//just to allow this to work without IEV/make it very easy to compare
		{
			#pragma omp parallel //expanded parallel --- to allow sample to be allocated once
			{
				float* sample = new float[numEchos];
				int start = omp_get_thread_num()/omp_get_num_threads()*xres*yres*num_ch;
				int end = (omp_get_thread_num()+1)/omp_get_num_threads()*xres*yres*num_ch;
				for(int i =start; i <end; i++)
				{
					/////////
					for(int j = 0; j < numEchos; j++)
						sample[j]=freq_ptr[i+j*xres*yres*num_ch];     //assuming all(6-10 at at time) pages can be held in memory, this isn't terrible
					
					weights[i]=stdev(sample, numEchos);		//find standard deviation between echoes
					/////				
				}
				delete[] sample;
			}
			
			#pragma omp parallel for private(ch)
			for(ch = 0; ch < num_ch; ch++)
			{	
				float* temp_array;
		
			
				channel_weights[ch]=&weights[ch*xres*yres];
				medianFilter(channel_weights[ch], xres, yres);
				for (int i = 0; i < xres*yres; i++)
				{
				  channel_weights[ch][i]=1/(channel_weights[ch][i]+FLT_MIN);		//weight as inverse, 
				}
			
			}
			
			for (int i = 0; i < xres*yres; i++)
				to_normalize[i]	= 0;	

			for(int ch=0; ch< num_ch; ch++)		
				for (int i = 0; i < xres*yres; i++)
				{
				to_normalize[i]+=channel_weights[ch][i];
				}
	
			for(int ch=0; ch< num_ch; ch++)		
				for (int i = 0; i < xres*yres; i++)
				{
				channel_weights[ch][i]/=to_normalize[i];			//normalize weights
				}
			
		}
		else
		{
			#pragma omp parallel for private(ch)
			for(int ch=0; ch< num_ch; ch++)	
			{
				channel_weights[ch]=&weights[ch*xres*yres];	
				for (int i = 0; i < xres*yres; i++)
				{
				channel_weights[ch][i]=1;			
				}
			}
		}
		for(e=0; e<numEchos; e++)
		{

			hdr_ptr[e].channels=1;
			hdr_ptr[e].contrast=e;
			hdr_ptr[e].data_type = ISMRMRD::ISMRMRD_FLOAT;//GADGET_IMAGE_REAL_FLOAT;
			hdr_ptr[e].image_type = ISMRMRD::ISMRMRD_IMTYPE_PHASE;//There is no frequency image type
			hdr_ptr[e].slice= (hdr_ptr[e].image_index) % num_slices;//was hdr_ptr[e].image_index___-1_____) % num_slices before decrementor was added upstream
						
			if(output_phase.value())
			{
				//
				GadgetContainerMessage<ISMRMRD::ImageHeader>* phase_hdr = new GadgetContainerMessage<ISMRMRD::ImageHeader>(hdr_ptr[e]);
				//*(phase_hdr->getObjectPtr()) =*(hdr_ptr[e]->getObjectPtr());
				GadgetContainerMessage<hoNDArray< float > > *comb_phase_msg = new GadgetContainerMessage<hoNDArray< float > >();
				phase_hdr->getObjectPtr()->image_series_index=series_id_offset+1;
				try{comb_phase_msg->getObjectPtr()->create(xres,yres);}	

				catch (std::runtime_error &err){
				GEXCEPTION(err,"Unable to create output image\n");
				return GADGET_FAIL;  
				}
				float* output_ptr=comb_phase_msg->getObjectPtr()->get_data_ptr();
				phase_hdr->cont(comb_phase_msg);
				//	
				for (int i = 0; i < xres*yres; i++)
				{
				output_ptr[i]=filtered_phase_ptr[e*xres*yres*num_ch+i]*channel_weights[0][i]; //instead of setting to 0 and adding first channel
				}
				for(int ch=1; ch< num_ch; ch++)	
					for (int i = 0; i < xres*yres; i++)
					{
						output_ptr[i]+=filtered_phase_ptr[e*xres*yres*num_ch+xres*yres*ch+i]*channel_weights[ch][i];; //instead of setting to 0 and adding first channel
					}						
				//
				if(meta)
				{
				GadgetContainerMessage<ISMRMRD::MetaContainer>* meta = new GadgetContainerMessage<ISMRMRD::MetaContainer>(attributes[e]); 
						
				comb_phase_msg->cont(meta);	
				
				}
				//
				if (this->next()->putq(phase_hdr) == -1) {
				m1->release();
					GERROR("Unable to put collapsed images on next gadget's queue\n");
				return GADGET_FAIL; 
				}
				
			}
			if(output_LFS.value())
			{
				//
				GadgetContainerMessage<ISMRMRD::ImageHeader>* freq_hdr=new GadgetContainerMessage<ISMRMRD::ImageHeader>(hdr_ptr[e]);
				//*(freq_hdr->getObjectPtr()) =*(hdr_ptr[e]->getObjectPtr());
				GadgetContainerMessage<hoNDArray< float > > *comb_freq_msg = new GadgetContainerMessage<hoNDArray< float > >();
				freq_hdr->getObjectPtr()->image_series_index=series_id_offset+output_phase.value()+1;
				try{comb_freq_msg->getObjectPtr()->create(xres,yres);}	

				catch (std::runtime_error &err){
				GEXCEPTION(err,"Unable to create output image\n");
				return GADGET_FAIL;  
				}
				float* output_ptr=comb_freq_msg->getObjectPtr()->get_data_ptr();
				freq_hdr->cont(comb_freq_msg);
				freq_hdr->getObjectPtr()->image_type = 6;
				//
				for (int i = 0; i < xres*yres; i++)
					output_ptr[i]=freq_ptr[e*xres*yres*num_ch+i]*channel_weights[0][i]; //instead of setting to 0 and adding first channel
				for(int ch=1; ch< num_ch; ch++)		
					for (int i = 0; i < xres*yres; i++)
					{
						output_ptr[i]+=freq_ptr[e*xres*yres*num_ch+xres*yres*ch+i]*channel_weights[ch][i];
					}
				//
				if(meta)
				{
				GadgetContainerMessage<ISMRMRD::MetaContainer>* meta = new GadgetContainerMessage<ISMRMRD::MetaContainer>(attributes[e]); 
				meta->getObjectPtr()->set(GADGETRON_DATA_ROLE, GADGETRON_IMAGE_FREQMAP);
				//*(meta->getObjectPtr())=*(attributes[e]->getObjectPtr());
				comb_freq_msg->cont(meta);	
				}
				//
				if (this->next()->putq(freq_hdr) == -1) {
				//m1->release();
					GERROR("Unable to put collapsed images on next gadget's queue\n");
				return GADGET_FAIL; 
				}
			
			}
			
			
		}
		delete[] to_normalize;
		delete[] weights;
		delete[] channel_weights;
		//if(output.value()==int(OUTPUT::PHASE))
		//	delete[] unfiltered_phase_ptr;
		

	}
	


		
	return GADGET_OK;
}