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;
}