//------------------------------------------------------------
// $Id: spc2PE.cc,v 1.1.1.1 1999/11/25 06:26:09 yamauchi Exp $
//------------------------------------------------------------
//	spc2PE.cc
//	部分空間と PE のマッピング
//	平成８年７月１１日(木)
//	Copyright (C) 1996--1998 YAMAUCHI Hitoshi 山内 斉
//	last change 1997年9月20日(土)
//------------------------------------------------------------
// #include <stdlib.h>
#include <assert.h>
// #include "constants.h"
#include "spc2PE.h"
#include "mpi2exit.h"

//------------------------------
// PE の次元を知る
//------------------------------
int getSystemDimension(const IntVec3& PEnum)
{
    int dimension = 3;		// PE 数が一つの軸の数を引いていく
    int i;
    for(i = 0; i < 3; i++)
    {
	assert(PEnum.get(i) > 0);
	if(PEnum.get(i) == 1)
	{
	    dimension--;
	}
    }
    if(dimension == 0)
    {
	dimension = 1;		// 1 つしか PE がない
    }
    if((dimension < 1) || (3 < dimension))
    {
	cerr << "Error! : illegal PE dimension at getSystemDimension" << endl;
	commMpi2_exit(1);
    }
    return(dimension);
}


//------------------------------
// base class
//------------------------------
spc2PEBaseClass::
spc2PEBaseClass(void)
{
    this->mSystemDimension = 0;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  		= -1;
	this->mNumberOfSPCof1PE[i] 	= -1;
    }
    this->mSubDivNum = -1;
    this->mPEID.set(-1, -1, -1);
}

// base class information print
void spc2PEBaseClass::
baseprint(void)
{
    cout << "spc2PEBase::system dimension " << this->mSystemDimension << endl;
    cout << "spc2PEBase::number of PEs    (" << this->mNumberOfPE[0] << 
    	", " << this->mNumberOfPE[1] << ", " << this->mNumberOfPE[2] << ")" << 
	endl;
    cout << "spc2PEBase::number of space of 1PE (" << 
    	this->mNumberOfSPCof1PE[0] << ", " << this->mNumberOfSPCof1PE[1] 
	<< ", " << this->mNumberOfSPCof1PE[2] << ")" << endl;
    cout << "spc2PEBase::space subdivision " << this->mSubDivNum << endl;
    cout << "spc2PEBase::PEID " << this->mPEID << endl;
}

//------------------------------------------------------------
// block allocation
//------------------------------------------------------------
spc2PEBlockClass::
spc2PEBlockClass(void)
{
    this->mSystemDimension = 0;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  		= -1;
	this->mNumberOfSPCof1PE[i] 	= -1;
    }
    this->mSubDivNum = -1;
    this->mPEID.set(-1, -1, -1);
}

spc2PEBlockClass::
spc2PEBlockClass(const spc2PEBlockClass& rhs)
{
    this->mSystemDimension = rhs.mSystemDimension;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  	   = rhs.mNumberOfPE[i];
	this->mNumberOfSPCof1PE[i] = rhs.mNumberOfSPCof1PE[i];
    }
    this->mSubDivNum = rhs.mSubDivNum;
    this->mPEID	     = rhs.mPEID;
}

//------------------------------
// init
//------------------------------
void spc2PEBlockClass::
init(const IntVec3& numberOfPEs, int subdivnum, const IntVec3& PEid)
{
    // block allocation に次元は関係ないが確認
    this->mSystemDimension = getSystemDimension(numberOfPEs); 
    this->mSubDivNum	   = subdivnum;    
    if(subdivnum < 1)
    {
	cerr << "Error! : illegal subdivnum spc2PEBlockClass::init" << 
	    subdivnum << endl;
	commMpi2_exit(1);
    }
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  = numberOfPEs.get(i);
	if((this->mNumberOfPE[i]  < 1) || 
	   ((this->mSubDivNum % this->mNumberOfPE[i]) != 0))
	{
	    //// 空間分割数(ex.32) PE(2,4,4) のように subdiv % pe == 0 が正しい
	    cerr << "Error! : illegal PE or space num PE [" << numberOfPEs
		<< "], spacenum [" << this->mSubDivNum << "]" << 
		    " spc2PEBlockClass::init" << endl;
	    commMpi2_exit(1);
	}
	this->mNumberOfSPCof1PE[i] = subdivnum / this->mNumberOfPE[i];
    }
    this->mPEID = PEid;
}

//------------------------------
// spcpos -> PEID
//------------------------------
const IntVec3 spc2PEBlockClass::
getPEIDfromSpcPos(const IntVec3& spcPos)
{
    assert(this->mSystemDimension > 0);
    // spcpos * PEnum / subdivnum
    static int i, pe_id[3];
    static IntVec3 PEid;
    for(i = 0; i < 3; i++)
    {
	assert(spcPos.get(i) >= 0);
	pe_id[i] = 
	    (spcPos.get(i) * this->mNumberOfPE[i]) / this->mSubDivNum;
    }
    PEid.set(pe_id[0], pe_id[1], pe_id[2]);

    return(PEid);
}

//------------------------------
// block allocation の local index
// spcpos - (1つの PE が担当する空間数(x,y,z) * 自分の PEID)
//------------------------------
const IntVec3 spc2PEBlockClass::
getLocalIdxFromSpcPos(const IntVec3& spcPos)
{
    static int local_idx[3], i;
    static IntVec3 localIdx;
    for(i = 0; i < 3; i++)
    {
	local_idx[i] = 
	    spcPos.get(i) - (this->mNumberOfSPCof1PE[i] * this->mPEID.get(i));
// 	assert((0 <= local_idx[i]) && 
// 	       (local_idx[i] < this->mNumberOfSPCof1PE[i]));
	if(!((0 <= local_idx[i]) && 
	     (local_idx[i] < this->mNumberOfSPCof1PE[i])))
	{
	    cout << "DEBUG : spcpos " << spcPos << endl;
	    this->print();
	}
    }
    localIdx.set(local_idx[0], local_idx[1], local_idx[2]);
    return(localIdx);
}

void spc2PEBlockClass::
print(void)
{
    this->baseprint();
}

//------------------------------------------------------------
// distributed allocation
//------------------------------------------------------------
spc2PEDistributeClass::
spc2PEDistributeClass(void)
{
    this->mSystemDimension = 0;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  		= -1;
	this->mNumberOfSPCof1PE[i] 	= -1;
    }
    this->mSubDivNum = -1;
    this->mPEID.set(-1, -1, -1);
}

spc2PEDistributeClass::
spc2PEDistributeClass(const spc2PEDistributeClass& rhs)
{
    this->mSystemDimension = rhs.mSystemDimension;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  	   = rhs.mNumberOfPE[i];
	this->mNumberOfSPCof1PE[i] = rhs.mNumberOfSPCof1PE[i];
    }
    this->mSubDivNum = rhs.mSubDivNum;
    this->mPEID	     = rhs.mPEID;
}

void spc2PEDistributeClass::
init(const IntVec3& numberOfPEs, int subdivnum, const IntVec3& PEid)
{
    // distributed allocation に次元は関係ないが確認
    this->mSystemDimension = getSystemDimension(numberOfPEs);
    this->mSubDivNum	   = subdivnum;    
    if(this->mSubDivNum < 1)
    {
	cerr << "Error! : illegal subdivnum spc2PEBlockClass::init" << 
	    subdivnum << endl;
	commMpi2_exit(1);
    }
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  = numberOfPEs.get(i);
	if((this->mNumberOfPE[i]  < 1)  || 
	   ((this->mSubDivNum % this->mNumberOfPE[i]) != 0))
	{
	    //// 空間分割数(ex.32) PE(2,4,4) のように subdiv % pe == 0 が正しい
	    cerr << "Error! : illegal PE or space num PE [" << numberOfPEs
		<< "], subdiv num [" << subdivnum << "]" << 
		    " spc2PEDistributeClass::init" << endl;
	    commMpi2_exit(1);
	}
	this->mNumberOfSPCof1PE[i] = subdivnum / this->mNumberOfPE[i];
    }
    this->mPEID = PEid;
}

//------------------------------
// get PEID
//------------------------------
const IntVec3 spc2PEDistributeClass::
getPEIDfromSpcPos(const IntVec3& spcPos)
{
    assert(this->mSystemDimension > 0);
    assert(spcPos.get(IntVec3::X) >= 0);
    assert(spcPos.get(IntVec3::Y) >= 0);
    assert(spcPos.get(IntVec3::Z) >= 0);

    static IntVec3 PEid;
    int pe_x = spcPos.get(IntVec3::X) % this->mNumberOfPE[0];
    int pe_y = spcPos.get(IntVec3::Y) % this->mNumberOfPE[1];
    int pe_z = spcPos.get(IntVec3::Z) % this->mNumberOfPE[2];
    PEid.set(pe_x, pe_y, pe_z);

    return(PEid);
}

//------------------------------
// get local idx 
//------------------------------
const IntVec3 spc2PEDistributeClass::
getLocalIdxFromSpcPos(const IntVec3& spcPos)
{
    static int local_idx[3], i;
    static IntVec3 localIdx;
    for(i = 0; i < 3; i++)
    {
	local_idx[i] = spcPos.get(i) / this->mNumberOfPE[i];
	assert((0 <= local_idx[i]) && 
	       (local_idx[i] < this->mNumberOfSPCof1PE[i]));
    }
    localIdx.set(local_idx[0], local_idx[1], local_idx[2]);

    return(localIdx);
}

void spc2PEDistributeClass::
print(void)
{
    this->baseprint();
}

//------------------------------------------------------------
// skewed distributed allocation
//------------------------------------------------------------
spc2PESkewClass::
spc2PESkewClass(void)
{
    this->mSystemDimension = 0;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  	   = -1;
	this->mNumberOfSPCof1PE[i] = -1;
    }
    this->mSubDivNum = -1;
    this->mPEID.set(-1, -1, -1);
    this->mPlaneDir = PE_ELSE_DIR;
}

spc2PESkewClass::
spc2PESkewClass(const spc2PESkewClass& rhs)
{
    this->mSystemDimension = rhs.mSystemDimension;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  	   = rhs.mNumberOfPE[i];
	this->mNumberOfSPCof1PE[i] = rhs.mNumberOfSPCof1PE[i];
    }
    this->mSubDivNum = rhs.mSubDivNum;
    this->mPEID	     = rhs.mPEID;
    this->mPlaneDir  = rhs.mPlaneDir;
}

void spc2PESkewClass::
init(const IntVec3& numberOfPEs, int subdivnum, const IntVec3& PEid)
{
    this->mSystemDimension = getSystemDimension(numberOfPEs);
    if((this->mSystemDimension < 1) || (2 < this->mSystemDimension))
    {
	cerr << "Error! : illegal system dimension [" << this->mSystemDimension
	    << "] spc2PESkewClass::init fail." << endl;
	commMpi2_exit(1);
    }
    this->mSubDivNum	   = subdivnum;    
    if(subdivnum < 1)
    {
	cerr << "Error! : illegal subdivnum spc2PEBlockClass::init" << 
	    subdivnum << endl;
	commMpi2_exit(1);
    }
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  = numberOfPEs.get(i);
	if((this->mNumberOfPE[i]  < 1)  || 
	   ((this->mSubDivNum % this->mNumberOfPE[i]) != 0))
	{
	    //// 空間分割数(ex.32) PE(2,4,4) のように subdiv % pe == 0 が正しい
	    cerr << "Error! : illegal PE or space num PE [" << numberOfPEs
		<< "], spacenum [" << subdivnum << "]" << 
		    "spc2PESkewClass::init" << endl;
	    commMpi2_exit(1);
	}
	this->mNumberOfSPCof1PE[i] = subdivnum / this->mNumberOfPE[i];
    }
    this->mPEID = PEid;

    // set plane dir
    switch(this->mSystemDimension)
    {
    case 1:			// 1 dimension
	if(this->mNumberOfPE[0] > 1) 
	{
	    this->mPlaneDir = PE_X_DIR;
	}else if(this->mNumberOfPE[1] > 1)
	{
	    this->mPlaneDir = PE_Y_DIR;	    
	}else
	{
	    this->mPlaneDir = PE_Z_DIR;	// or there is only 1 PE 
	}
	break;

    case 2:			// 2 dimension
	if((this->mNumberOfPE[0] > 1) && (this->mNumberOfPE[1] > 1))
	{
	    // XY - plane (normal = Z plane)
	    this->mPlaneDir = PE_Z_DIR;
	}else if((this->mNumberOfPE[1] > 1) && (this->mNumberOfPE[2] > 1))
	{
	    // YZ - plane (normal = X plane)
	    this->mPlaneDir = PE_X_DIR;
	}else if((this->mNumberOfPE[2] > 1) && (this->mNumberOfPE[0] > 1))
	{
	    // ZX - plane (normal = Y plane)
	    this->mPlaneDir = PE_Y_DIR;
	}else
	{
	    cout << "Error! : PE plane is not found." << endl;
	    cout << "\tSystemDimension = " << this->mSystemDimension << endl;
	    cout << "\tNumberOfPE (" << this->mNumberOfPE[0] << ", " << 
		this->mNumberOfPE[1] << ", " << this->mNumberOfPE[2] << ")\n";
	    cout << "\tSpcInPE (" << this->mNumberOfSPCof1PE[0] << ", " << 
		this->mNumberOfSPCof1PE[1] << ", " << 
		    this->mNumberOfSPCof1PE[2] << ")\n";
	    cout << "\tSubdivNum = " << this->mSubDivNum << endl;
	    commMpi2_exit(1);
	}
	break;
	
    default:
	cout << "Error! : PE plane dir is ambiguous." << endl;	
	commMpi2_exit(1);	
    }
}

//------------------------------
// get PE id (for skewed-distributed allocation 1dim, 2dim, 3dim)
//------------------------------
// for 1D (x, y, z = spcpos x, y, z)
// #ifdef PE_IS_XDIR
//     int cl_x = (x + y + z) % (SysInfo.getPENum()).get(IntVec3::X);
//     int cl_y = 0; 
//     int cl_z = 0; 
// #elif  PE_IS_YDIR
//     int cl_x = 0; 
//     int cl_y = (x + y + z) % (SysInfo.getPENum()).get(IntVec3::Y);
//     int cl_z = 0;
// #elif  PE_IS_ZDIR
//     int cl_x = 0; 
//     int cl_y = 0;
//     int cl_z = (x + y + z) % (SysInfo.getPENum()).get(IntVec3::Z);
//---------------
inline const IntVec3 spc2PESkewClass::
getPE1DID(const IntVec3& spcpos) const
{
    assert(this->mSystemDimension == 1);
    static IntVec3 PEID;
    static int pe_x, pe_y, pe_z, sumsp;
    pe_x = 0;
    pe_y = 0;
    pe_z = 0;
    sumsp = spcpos.get(IntVec3::X) + spcpos.get(IntVec3::Y) + 
	spcpos.get(IntVec3::Z);

    switch(this->mPlaneDir) 
    {
    case PE_X_DIR:
	pe_x = sumsp % this->mNumberOfPE[0];
	break;
    case PE_Y_DIR:
	pe_y = sumsp % this->mNumberOfPE[1];
	break;
    case PE_Z_DIR:
	pe_z = sumsp % this->mNumberOfPE[2];
	break;
    default:
	cout << "Error! : illegal PE plane dir at spc2PESkewClass::getPE1DID"
	    << endl;
	commMpi2_exit(1);
    }
    PEID.set(pe_x, pe_y, pe_z);

    return(PEID);
}

//---------------
// for 2dim (sx, sy, sz = spcpos x, y, z)
// #ifdef PE_IS_NO_Z_DIR
//     int cl_x = (sx + sz) % (SysInfo.getPENum()).get(IntVec3::X);
//     int cl_y =       sy  % (SysInfo.getPENum()).get(IntVec3::Y);
//     int cl_z = 0;
//     assert((SysInfo.getPENum()).get(IntVec3::Z) == 1); // Z方向にはない2次元
// #elif  PE_IS_NO_X_DIR
//     int cl_x = 0;
//     int cl_y = (sy + sx) % (SysInfo.getPENum()).get(IntVec3::Y);
//     int cl_z =       sz  % (SysInfo.getPENum()).get(IntVec3::Z);
//     assert((SysInfo.getPENum()).get(IntVec3::X) == 1); // X方向にはない2次元
// #elif  PE_IS_NO_Y_DIR
//     int cl_x =       sx  % (SysInfo.getPENum()).get(IntVec3::X);
//     int cl_y = 0;
//     int cl_z = (sz + sy) % (SysInfo.getPENum()).get(IntVec3::Z);
//---------------
inline const IntVec3 spc2PESkewClass::
getPE2DID(const IntVec3& spcpos) const
{
    assert(this->mSystemDimension == 2);
    static IntVec3 PEID;
    static int pe_x, pe_y, pe_z, sx, sy, sz;
    sx = spcpos.get(IntVec3::X);
    sy = spcpos.get(IntVec3::Y);
    sz = spcpos.get(IntVec3::Z);
    
    switch(this->mPlaneDir)
    {
    case PE_X_DIR:		// YZ plane
	pe_x = 0;
	pe_y = (sy + sx) % this->mNumberOfPE[1];
	pe_z =       sz  % this->mNumberOfPE[2];
	assert(this->mNumberOfPE[0] == 1); // X方向にはない2次元
	break;

    case PE_Y_DIR:		// ZX plane
	pe_x =       sx  % this->mNumberOfPE[0];
	pe_y = 0;
	pe_z = (sz + sy) % this->mNumberOfPE[2];
	assert(this->mNumberOfPE[1] == 1); // Y方向にはない2次元	
	break;

    case PE_Z_DIR:		// XY plane
	pe_x = (sx + sz) % this->mNumberOfPE[0];
	pe_y =       sy  % this->mNumberOfPE[1];
	pe_z = 0;
	assert(this->mNumberOfPE[2] == 1); // Z方向にはない2次元
	break;

    default:
	cout << "Error! : illegal planedir at spc2PESkewClass::getPE2DID"
	    << endl;
	commMpi2_exit(1);
	break;
    }
    PEID.set(pe_x, pe_y, pe_z);
    return(PEID);
}

//------------------------------
// getPE ID for skewed-distributed allocation
//------------------------------
const IntVec3 spc2PESkewClass::
getPEIDfromSpcPos(const IntVec3& spcPos)
{
    assert(spcPos.get(IntVec3::X) >= 0);
    assert(spcPos.get(IntVec3::Y) >= 0);
    assert(spcPos.get(IntVec3::Z) >= 0);
    switch(this->mSystemDimension)
    {
    case 1:
	return(this->getPE1DID(spcPos));
	break;
    case 2:	
	return(this->getPE2DID(spcPos));
	break;
    case 3:
    default:
	cout << "Internal Error! : no such system dimension for " << 
	    "skewed-distributed allocation " << this->mSystemDimension << endl;
	commMpi2_exit(1);
	break;
    }
    return(IntVec3(-1, -1, -1));
}

//------------------------------------------------------------
// getPE local index of space array 
//  	skewed-distributed allocation
//------------------------------------------------------------
// for 1dim
//------------------------------
inline const IntVec3 spc2PESkewClass::
getPE1DLocalSpaceIndex(const IntVec3& spcpos) const
{
    assert(this->mSystemDimension == 1);
    static IntVec3 localIdx;
    static int PEdir, other1, other2, sidx[3];
    switch(this->mPlaneDir) 
    {
    case PE_X_DIR:
	PEdir 	= 0;	other1	= 1;	other2	= 2;
	break;
    case PE_Y_DIR:
	PEdir 	= 1;	other1	= 2;	other2	= 0;
	break;
    case PE_Z_DIR:
	PEdir 	= 2;	other1	= 0;	other2	= 1;
	break;
    default:
	cout << "Error! : illegal PE plane dir at spc2PESkewClass::"
	    "getPE1DLocalSpaceIndex" << endl;
	commMpi2_exit(1);
    }
    sidx[0] = spcpos.get(IntVec3::X);
    sidx[1] = spcpos.get(IntVec3::Y);
    sidx[2] = spcpos.get(IntVec3::Z);
    // skewbias : skew によって発生する distributed allocation からのずれ
    int skewbias = (sidx[other1] + sidx[other2]) % this->mNumberOfPE[PEdir];
    sidx[PEdir]  = 
	((sidx[PEdir] - skewbias) + this->mSubDivNum) % this->mSubDivNum; 

    // ここまでで distributed allocation と同じになった
    sidx[PEdir] /= this->mNumberOfPE[PEdir];

    assert((0 <= sidx[0]) && (sidx[0] < this->mNumberOfSPCof1PE[0]));
    assert((0 <= sidx[1]) && (sidx[1] < this->mNumberOfSPCof1PE[1]));
    assert((0 <= sidx[2]) && (sidx[2] < this->mNumberOfSPCof1PE[2]));

    localIdx.set(sidx[0], sidx[1], sidx[2]);
    return(localIdx);
}

//------------------------------
// for 2dim
//------------------------------
inline const IntVec3 spc2PESkewClass::
getPE2DLocalSpaceIndex(const IntVec3& spcpos) const
{
    assert(this->mSystemDimension == 2);
    static IntVec3 localIdx;
    static int PEnormZ, PEdirX, PEdirY, sidx[3], lidx[3];
    switch(this->mPlaneDir)
    {
    case PE_X_DIR:		// YZ plane
	PEdirX = 1;	PEdirY = 2;	PEnormZ = 0;
	assert(this->mNumberOfPE[0] == 1); // X方向にはない2次元
	break;

    case PE_Y_DIR:		// ZX plane
	PEdirX = 2;	PEdirY = 0;	PEnormZ = 1;
	assert(this->mNumberOfPE[1] == 1); // Y方向にはない2次元	
	break;

    case PE_Z_DIR:		// XY plane
	PEdirX = 0;	PEdirY = 1;	PEnormZ = 2;
	assert(this->mNumberOfPE[2] == 1); // Z方向にはない2次元
	break;

    default:
	cout << "Error! : illegal PE plane dir at spc2PESkewClass::"
	    "getPE2DLocalSpaceIndex" << endl;
	commMpi2_exit(1);
    }
    sidx[0] = spcpos.get(IntVec3::X);
    sidx[1] = spcpos.get(IntVec3::Y);
    sidx[2] = spcpos.get(IntVec3::Y);
    int skewbias = sidx[PEnormZ] % this->mNumberOfPE[PEdirX];
    sidx[PEdirX] = 
	((sidx[PEdirX] - skewbias) + this->mSubDivNum) % this->mSubDivNum;

    // ここまでで distributed allocation と同じになった
    lidx[PEdirX]  = sidx[PEdirX]  / this->mNumberOfPE[PEdirX];
    lidx[PEdirY]  = sidx[PEdirY]  / this->mNumberOfPE[PEdirY];
    lidx[PEnormZ] = sidx[PEnormZ];

    assert((0 <= lidx[0]) && (lidx[0] < this->mNumberOfSPCof1PE[0]));
    assert((0 <= lidx[1]) && (lidx[1] < this->mNumberOfSPCof1PE[1]));
    assert((0 <= lidx[2]) && (lidx[2] < this->mNumberOfSPCof1PE[2]));
    
    localIdx.set(lidx[0], lidx[1], lidx[2]);
    return(localIdx);
}

//------------------------------
// get local space array index 
//   各 PE の持つ local な空間情報配列の index を部分空間位置から返す
//------------------------------
const IntVec3 spc2PESkewClass::
getLocalIdxFromSpcPos(const IntVec3& spcPos)
{
    switch(this->mSystemDimension)
    {
    case 1:
	return(this->getPE1DLocalSpaceIndex(spcPos));
	break;
    case 2:
	return(this->getPE2DLocalSpaceIndex(spcPos));
	break;
    case 3:
    default:
	cout << "Internal Error! : no such system dimension for " << 
	    "skewed-distributed allocation " << this->mSystemDimension << endl;
	commMpi2_exit(1);
	break;
    }
    commMpi2_exit(1);
    return(spcPos);
}

void spc2PESkewClass::
print(void)
{
    this->baseprint();
    const char *dir[] = {"X_DIR", "Y_DIR", "Z_DIR", "ELSE_DIR", };
    cout << "spc2PESkew:: plane dir = " << dir[this->mPlaneDir] << endl;
}


//------------------------------------------------------------
// random allocation
//------------------------------------------------------------
// constructor 
//------------------------------
spc2PERandomClass::
spc2PERandomClass(void)
{
    this->mSystemDimension = 0;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  	   = -1;
	this->mNumberOfSPCof1PE[i] = -1;
    }
    this->mSubDivNum = -1;
    this->mPEID.set(-1, -1, -1);
}

spc2PERandomClass::
spc2PERandomClass(const spc2PERandomClass& rhs)
{
    this->mSystemDimension = rhs.mSystemDimension;
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  	   = rhs.mNumberOfPE[i];
	this->mNumberOfSPCof1PE[i] = rhs.mNumberOfSPCof1PE[i];
    }
    this->mSubDivNum = rhs.mSubDivNum;
    this->mPEID	     = rhs.mPEID;
}

//------------------------------
// init for random allocation
//------------------------------
void spc2PERandomClass::
init(const IntVec3& numberOfPEs, int subdivnum, const IntVec3& PEid)
{
    // random allocation に次元は関係ないが
    // 現在は 1 次元のみ
    this->mSystemDimension = getSystemDimension(numberOfPEs); 
    if((this->mSystemDimension != 1) 	 ||
       (numberOfPEs.get(IntVec3::Y) > 1) ||
       (numberOfPEs.get(IntVec3::Z) > 1))
    {
	cerr << "Error! : illegal dimension spc2PERandomClass::init" 
	    << " only xdir 1 dim is permitted, but now (" <<
		numberOfPEs << ")." << endl;  
	commMpi2_exit(1);
    }

    this->mSubDivNum	   = subdivnum;    
    if(subdivnum < 1)
    {
	cerr << "Error! : illegal subdivnum spc2PERandomClass::init" << 
	    subdivnum << endl;
	commMpi2_exit(1);
    }
    int i;
    for(i = 0; i < 3; i++)
    {
	this->mNumberOfPE[i]  = numberOfPEs.get(i);
	// random mapping ではどの PE がどれだけの空間を持つのか
	// も不明である。そのため全て持つ
	this->mNumberOfSPCof1PE[i] = subdivnum;
    }
    this->mPEID = PEid;
}

//------------------------------
// hash function
//   ここで random なマッピングをシミュレートする
//------------------------------
inline int spc2PERandomClass::
spcMapHash(const IntVec3& spcPos)
{
    int x = spcPos.get(IntVec3::X);
    int y = spcPos.get(IntVec3::Y);
    int z = spcPos.get(IntVec3::Z);
    
    return((x * 3 + y * 5 + z * 7) % (this->mNumberOfPE[0]));
}

//------------------------------
// spcpos -> PE index
//------------------------------
const IntVec3 spc2PERandomClass::
getPEIDfromSpcPos(const IntVec3& spcPos)
{
    return(IntVec3(spcMapHash(spcPos), 0, 0));
}

//------------------------------
// random では local 空間を圧縮する方法がない可能性があるので全てを保
// 持する。 
//------------------------------
const IntVec3 spc2PERandomClass::
getLocalIdxFromSpcPos(const IntVec3& spcPos)
{
    return(spcPos);
}

void spc2PERandomClass::
print(void)
{
    this->baseprint();
}
