#
# $Date: 2006/10/31 13:51:01 $
# $Id: Grid.pm,v 1.2 2006/10/31 13:51:01 gelpi Exp $
# $Revision: 1.2 $
#
package CMIP::Grid;

=head1 NAME

CMIP::Grid - Grid details for CMIP calculation

=head1 SYNOPSIS

use CMIP::Grid;

$gr = CMIP::Grid->new;

=head1 METHODS

$value=$gr->readGrid($readGrid);

$value=$gr->perfill($perfill);

@array=$gr->int(@array);

@array=$gr->cen(@array);

@array=$gr->dim(@array);

$txt=$gr->asParamString($g) # $g true for outer grid

@array=$gr->origin;

@array=$gr->size;

$value=$gr->ngrid;

$index=$gr->mapindex($i,$j,$k);

$ijk=$gr->getijk($index);

$xyz=$gr->getxyz($index);

=cut

use strict;

1;

sub new {
	my $class = shift;
	my $self = { 
		readGrid => 0,
		int => {x => 0.5, y => 0.5, z => 0.5},
		dim => {i => 64, j => 64,  k => 64},
		cen => {x => 0.0, y => 0.0, z => 0.0},
		perfill => 0.8,				
	};
	_update($self);
	bless $self;
}


sub asParamString {
	my ($self, $gr) = @_;
	my $g;
	if ($gr) {$g = "0"} else {$g =""};
	if ($self->{readgrid} == 0) {
		return qq (  READGRID$g = 0,
  CENX$g = $self->{cen}->{x}, CENY$g = $self->{cen}->{y}, CENZ$g = $self->{cen}->{z}
  DIMX$g = $self->{dim}->{i}, DIMY$g = $self->{dim}->{j}, DIMZ$g = $self->{dim}->{k}
  INTX$g = $self->{int}->{x}, INTY$g = $self->{int}->{y}, INTZ$g = $self->{int}->{z}
 );
 	} elsif ($self->{readgrid} == 3) {
		return qq (  READGRID$g = 3,
  CENX$g = $self->{cen}->{x}, CENY$g = $self->{cen}->{y}, CENZ$g = $self->{cen}->{z}
  DIMX$g = $self->{dim}->{i}, DIMY$g = $self->{dim}->{j}, DIMZ$g = $self->{dim}->{k}
  INTX$g = $self->{int}->{x}, INTY$g = $self->{int}->{y}, INTZ$g = $self->{int}->{z}
 );
	
 	} elsif ($self->{readgrid} == 1) {
 		return "  READGRID$g = 1,\n"
	} elsif ($self->{readgrid} == 2) {
		return qq (  READGRID$g = 2, PERFILL$g = $self->{perfill},
  INTX$g = $self->{int}->{x}, INTY$g = $self->{int}->{y}, INTZ$g = $self->{int}->{z}
  );
	} elsif ($self->{readgrid} > 3) {
		return qq (  READGRID$g = $self->{readgrid}, PERFILL$g = $self->{perfill},
  INTX$g = $self->{int}->{x}, INTY$g = $self->{int}->{y}, INTZ$g = $self->{int}->{z}
  );
	}
}

sub readGrid {
	my ($self, $r) = @_;
	$self->{readgrid} = $r if $r;
	$self->{needUpdate}=1 if $r;
	return $self->{readgrid}
}

sub perfill {
	my ($self, $p) = @_;
	$self->{perfill} = $p if $p;
	$self->{needUpdate}=1 if $p;
	return $self->{perfill}
}

sub int {
	my ($self, @p) = @_;
	($self->{int}->{x}, $self->{int}->{y}, $self->{int}->{z}) = @p if @p;
	$self->{needUpdate}=1 if @p;
	return ($self->{int}->{x}, $self->{int}->{y}, $self->{int}->{z})
}

sub cen {
	my ($self, @p) = @_;
	($self->{cen}->{x}, $self->{cen}->{y}, $self->{cen}->{z}) = @p if @p;
	$self->{needUpdate}=1 if @p;
	return ($self->{cen}->{x}, $self->{cen}->{y}, $self->{cen}->{z})
}
sub dim {
	my ($self, @p) = @_;
	if (@p) {
		grep ($_=CORE::int($_),@p);
		($self->{dim}->{i}, $self->{dim}->{j}, $self->{dim}->{k}) = @p;
		$self->{needUpdate}=1
	}
	return ($self->{dim}->{i}, $self->{dim}->{j}, $self->{dim}->{k})
}
 
sub ngrid {
	my $self = shift;
	_update($self);
	return $self->{ngrid}
}

sub size {
	my $self = shift;
	_update($self);
	return ($self->{size}->{x}, $self->{size}->{y}, $self->{size}->{z})
}

sub origin {
	my $self = shift;
	_update($self);
	return ($self->{origin}->{x}, $self->{origin}->{y}, $self->{origin}->{z})
}

sub mapindex {
	my ($self, $i, $j, $k) = @_;
	my ($i1,$i2,$i3) = $self->_getDimVec;
	return ($k-1)*($i2+1)*($i1+1)+($j-1)*($i1+1)+$i;
}

sub mapijk {
	my ($self, $idgrid) = @_;
	my ($i1,$i2,$i3) = $self->_getDimVec;
	my $kg=1+CORE::int($idgrid/($i1+1)/($i2+1));
        my $j=$idgrid-($kg-1)*($i1+1)*($i2+1);
        my $jg=1+CORE::int($j/($i1+1));
        my $ig=$j-($jg-1)*($i1+1);
# afegir per evitar problemes de paret en i i j
	if ($ig == 0) {
		$jg--;
		$ig=$i1+1
	}
	if ($jg == 0) {
		$kg--;
		$jg=$i2+1
	}
	return ($ig, $jg, $kg);
}

sub xyz2grid {
	my ($self, $x, $y, $z) = @_;
	my ($x1,$y1,$z1) = $self->_getOriginVec;
	my ($xs,$ys,$zs) = $self->_getIntVec;
	return (($x-$x1)/$xs+1, ($z-$z1)/$zs+1, ($z-$z1)/$zs+1);
}
	
sub grid2xyz {
	my ($self, $i, $j, $k) = @_;
	my ($x1,$y1,$z1) = $self->_getOriginVec;
	my ($xs,$ys,$zs) = $self->_getIntVec;
	return ($x1+($i-1)*$xs,	$y1+($j-1)*$ys, $z1+($k-1)*$zs);
}
	

####Private

sub _getDimVec {
	my $self = shift;
	return ($self->{dim}->{i},$self->{dim}->{j},$self->{dim}->{k});
}

sub _getOriginVec {
	my $self = shift;
	return ($self->{origin}->{x},$self->{origin}->{y},$self->{origin}->{z});
}

sub _getIntVec {
	my $self = shift;
	return ($self->{int}->{x},$self->{int}->{y},$self->{int}->{z});
}

sub _update {
	my $self = shift;
	if ($self->{needUpdate}) {
		_calcNgrid($self);
		_calcOrigin($self);
		_calcSize($self);
		$self->{needUpdate}=0;
	}
	return $self
}

sub _calcNgrid {
	my $self = shift;
	$self->{ngrid} = ($self->{dim}->{i} + 1) * ($self->{dim}->{j} + 1) * ($self->{dim}->{k} + 1);
	return $self
}

sub _calcOrigin {
	my $self = shift;
	$self->{origin}->{x} = $self->{cen}->{x} - 0.5 *  $self->{int}->{x} * $self->{dim}->{i};
	$self->{origin}->{y} = $self->{cen}->{y} - 0.5 *  $self->{int}->{y} * $self->{dim}->{j};
	$self->{origin}->{z} = $self->{cen}->{z} - 0.5 *  $self->{int}->{z} * $self->{dim}->{k};
	return $self
}

sub _calcSize {
	my $self = shift;
	$self->{size}->{x} = $self->{int}->{x} * $self->{dim}->{i};
	$self->{size}->{y} = $self->{int}->{y} * $self->{dim}->{j};
	$self->{size}->{z} = $self->{int}->{z} * $self->{dim}->{k};
}
