content: /*
   * Copyright (C) 2014 - Martin Berger
   * Copyright (C) 2017 - Christopher Syben
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */
  package edu.stanford.rsl.conrad.data.generic.complex;
  
  import java.util.Arrays;
  
  import edu.stanford.rsl.conrad.data.generic.datatypes.Complex;
  import edu.stanford.rsl.conrad.data.numeric.Grid1D;
  
  /**
   * Class to use complex numbers in a grid structure.
   * Internally float arrays are used. The real and imaginary parts are stored in an alternating manner.
   * @author akmaier / berger
   *
   */
  public class ComplexGrid1D extends ComplexGrid {
  	
  	/** Linear float array stores the complex numbers in an alternating manner [Re1, Imag1, Re2, Imag2, ..., ReN,ImagN]. */
  	private float[] buffer;
  	
  	/** offset for shifted access due to the compatibility with a Grid2DComplex. */
  	private int offset = 0;
  	
  	public ComplexGrid1D(int width) {
  		buffer = new float[width*2];
  		this.size = new int[] {width};
  		this.offset = 0;
  		init();
  		notifyAfterWrite();
  	}
  	
  	public ComplexGrid1D(float[] buffer, int offset, int width){
  		this.buffer = buffer;
  		this.size = new int[] {width};
  		this.offset = offset;
  		init();
  		notifyAfterWrite();
  	}
  	
  	public ComplexGrid1D(Grid1D grid){
  		this(grid.getSize()[0]);
  		final int inputSize = grid.getSize()[0];
  		for (int i=0; i < inputSize;++i){
  			this.setAtIndex(i, grid.getAtIndex(i));
  		}
  		this.size = new int[]{grid.getSize()[0]};
  		this.origin = new double[]{grid.getOrigin()[0]};
  		this.spacing = new double[]{grid.getSpacing()[0]};
  		this.offset = 0;
  		notifyAfterWrite();
  	}
  
  	public ComplexGrid1D(ComplexGrid1D grid){
  		this(grid.getSize()[0]);
  		final int inputSize = grid.getSize()[0];
  		for (int i=0; i < inputSize;++i){
  			this.setAtIndex(i, grid.getAtIndex(i));
  		}
  		this.size = new int[]{grid.size[0]};
  		this.origin = new double[]{grid.origin[0]};
  		this.spacing = new double[]{grid.spacing[0]};
  		this.offset = 0;
  		if(grid.openCLactive)
  			activateCL();
  	}
  	
  	public void init(){
  		this.origin = new double[]{0};
  		this.spacing = new double[]{1};
  	}
  	
  	public void fftshift(){
  		int width = this.size[0];
  		int startIndex = offset*2;
  		int endIndex = startIndex+(width*2);
  		int pW = (int)Math.ceil(width/2.0); 
  		
  		float[] tmpArr = Arrays.copyOfRange(buffer, startIndex, endIndex);
  		for(int i = pW; i < this.getSize()[0];i++)
  		{
  			buffer[startIndex+(i-pW)*2] = tmpArr[(i)*2];
  			buffer[startIndex+(i-pW)*2+1] = tmpArr[(i)*2+1];
  		}
  		for(int i = 0; i < pW;i++)
  		{
  			buffer[startIndex + (i+width-pW)*2] = tmpArr[(i)*2];
  			buffer[startIndex + (i+width-pW)*2+1] = tmpArr[(i)*2+1];
  		}		
  	}
  	
  	public void multiplyAtIndex(int index, float val) {
  		multiplyAtIndex(index, val,0);
  	}
  	
  	public void multiplyAtIndex(int index, float real, float imag) {
  		Complex in = new Complex(real,imag);
  		multiplyAtIndex(index,in);
  	}
  	
  	public void multiplyAtIndex(int index, Complex in) {
  		setAtIndex(index, getAtIndex(index).mul(in));
  	}
  	
  	
  	public void divideAtIndex(int index, float val) {
  		divideAtIndex(index, val, 0);
  	}
  	
  	public void divideAtIndex(int index, float real, float imag) {
  		Complex in = new Complex(real,imag);
  		divideAtIndex(index,in);
  	}
  	
  	public void divideAtIndex(int index, Complex in) {
  		setAtIndex(index, getAtIndex(index).div(in));
  	}
  	
  	
  	public void addAtIndex(int index, float val) {
  		addAtIndex(index, val, 0);
  	}
  	
  	public void addAtIndex(int index, float real, float imag) {
  		Complex in = new Complex(real,imag);
  		addAtIndex(index,in);
  	}
  	
  	public void addAtIndex(int index, Complex in) {
  		setAtIndex(index, getAtIndex(index).add(in));
  	}
  	
  	
  	public void subtractAtIndex(int index, float val) {
  		subtractAtIndex(index, val, 0);
  	}
  	
  	public void subtractAtIndex(int index, float real, float imag) {
  		Complex in = new Complex(real,imag);
  		subtractAtIndex(index,in);
  	}
  	
  	public void subtractAtIndex(int index, Complex in) {
  		setAtIndex(index, getAtIndex(index).sub(in));
  	}
  	
  	
  	
  	public void setAtIndex(int index, float val){
  		setAtIndex(index,val,0);
  	}
  	
  	public void setAtIndex(int index, float real, float imag){
  		Complex in = new Complex(real,imag);
  		setAtIndex(index, in);
  	}
  	
  	public void setAtIndex(int index, Complex val){
  		buffer[(index+offset)*2]=(float)val.getReal();
  		buffer[(index+offset)*2+1]=(float)val.getImag();
  		notifyAfterWrite();
  	}
  	
  	public Complex getAtIndex(int index){
  		notifyBeforeRead();
  		return new Complex(buffer[(index+offset)*2],buffer[(index+offset)*2+1]);
  	}
  	
  	
  	
  	public Grid1D getRealGrid(){
  		return getRealSubGrid(0, this.size[0]);
  	}
  	
  	public Grid1D getImagGrid(){
  		return getImagSubGrid(0, this.size[0]);
  	}
  	
  	public Grid1D getMagGrid(){
  		return getMagSubGrid(0, this.size[0]);
  	}
  	
  	public Grid1D getPhaseGrid(){
  		return getPhaseSubGrid(0, this.size[0]);
  	}
  	
  	public Grid1D getRealSubGrid(final int startIndex, final int length){
  		Grid1D subgrid = new Grid1D(length);
  		for (int i=0; i < length; ++i){
  			subgrid.setAtIndex(i, (float)this.getAtIndex(startIndex+i).getReal());
  		}
  		return subgrid;
  	}
  	
  	public Grid1D getImagSubGrid(final int startIndex, final int length){
  		Grid1D subgrid = new Grid1D(new float [length]);
  		for (int i=0; i < length; ++i){
  			subgrid.setAtIndex(i, (float)this.getAtIndex(startIndex+i).getImag());
  		}
  		return subgrid;
  	}
  	
  	public Grid1D getMagSubGrid(final int startIndex, final int length){
  		Grid1D subgrid = new Grid1D(new float [length]);
  		for (int i=0; i < length; ++i){
  			subgrid.setAtIndex(i, (float)this.getAtIndex(startIndex+i).getMagn());
  		}
  		return subgrid;
  	}
  	
  	public Grid1D getPhaseSubGrid(final int startIndex, final int length){
  		Grid1D subgrid = new Grid1D(new float [length]);
  		for (int i=0; i < length; ++i){
  			subgrid.setAtIndex(i, (float)this.getAtIndex(startIndex+i).getAngle());
  		}
  		return subgrid;
  	}
  
  	@Override
  	public Complex getValue(int... idx) {
  		return this.getAtIndex(idx[0]);
  	}
  	
  	@Override
  	public void setValue(Complex val, int... idx) {
  		setAtIndex(idx[0], val);
  	}
  
  	@Override
  	public ComplexGrid clone() {
  		notifyBeforeRead();
  		return new ComplexGrid1D(this);
  	}
  
  	@Override
  	public String toString() {
  		String result = new String();
  		result += "[";
  		for (int i = 0; i < size[0]; ++i) {
  			if (i != 0) result += ", ";
  			result += getAtIndex(i);
  		}
  		result += "]";
  		return result;
  	}
  	
  	public float[] getBuffer() {
  		notifyBeforeRead();
  		return buffer;
  	}
  	
  	public int getOffset() {
  		return offset;
  	}
  
  	@Override
  	public float[] getAslinearMemory() {
  		notifyBeforeRead();
  		return buffer;
  	}
  
  	@Override
  	public void setAslinearMemory(float[] buffer) {
  		this.buffer = buffer;
  		notifyAfterWrite();
  	}
  	
  	@Override
  	public float getRealAtIndex(int... idx) {
  		notifyBeforeRead();
  		return buffer[2*(offset+idx[0])];
  	}
  
  	@Override
  	public void setRealAtIndex(float val, int... idx) {
  		buffer[2*(offset+idx[0])] = val;
  		notifyAfterWrite();
  	}
  
  	@Override
  	public float getImagAtIndex(int... idx) {
  		notifyBeforeRead();
  		return buffer[2*(idx[0]+offset)+1];
  	}
  
  	@Override
  	public void setImagAtIndex(float val, int... idx) {
  		buffer[2*(idx[0]+offset)+1] = val;
  		notifyAfterWrite();
  	}
  	
  }
  
  