PathGeneratorFactory::PathGeneratorFactory(const boost::shared_ptr<StochasticProcessArray>& processes,
										   const TimeGrid& timeGrid)
: processes_(processes), grid_(timeGrid)
{
	unsigned long myseed = static_cast<unsigned long>(1);
	rand_ = std::tr1::mt19937(myseed);

	this->numAssets_ = processes->size();
	this->pathSize_ = timeGrid.size();

	PseudoRandom::rsg_type gen =
		PseudoRandom::make_sequence_generator(numAssets_*(timeGrid.size()-1),1);

	gen_ = boost::shared_ptr<MultiVariate<PseudoRandom>::path_generator_type>(new MultiVariate<PseudoRandom>::path_generator_type(processes,
                                timeGrid, gen, false));
				
	this->next_ = MultiPath(numAssets_,this->grid_);

	S0_ = std::valarray<double>(numAssets_);
	randArrs_ = std::valarray<double>(numAssets_);

	//this->testRandom_ = Array(numAssets_ * pathSize_);
	previousRand_ = Matrix(numAssets_, pathSize_);

	Matrix corr = processes->correlation();
	chol_=CholeskyDecomposition(corr);

	random_ = MultiPath(numAssets_,timeGrid);

	// num - 1
	this->muGrid_ = Matrix(numAssets_, timeGrid.size() - 1);
	this->volGrid_ = Matrix(numAssets_,timeGrid.size() - 1);

	antitheticFlag_ = false;

	for (Size asset = 0 ; asset<numAssets_ ;++asset)
	{
		//초기화 수익률 or 절대값
		S0_[asset] = processes->process(asset)->x0() / processes->process(asset)->basePrice();

		for (Size t = 0 ; t < pathSize_ - 1 ;++t)
		{
			double mu_t = processes->process(asset)->drift(timeGrid[t],1.0);
			double sigma_t = processes->process(asset)->diffusion(timeGrid[t],1.0);
			double dt_t = timeGrid.dt(t);

			// exp( ( mu[t] - 0.5 * vol[t] * vol[t] ) * dt[t] )
			muGrid_[asset][t] = std::exp( ( mu_t - 0.5 * sigma_t * sigma_t ) * dt_t );

			//  vol[t] * sqrt(dt[t]) 
			volGrid_[asset][t] = sigma_t * std::sqrt(dt_t);
		}

	}
}
 inline void populateSigmaPoints(StateVector mu_mat, StateCovarianceMatrix sigma_mat, double gamma_val, SigmaPointMatrix& X_mat)
 {
   sigma_mat *= (n + lambda);
   StateCovarianceMatrix sigma_root = CholeskyDecomposition(sigma_mat);
   X_mat[0] = mu_mat;
   for(unsigned int i = 1; i < NumStates; i++)
   {
     X_mat[i] = mu_mat + sigma_root.col(i);
     X_mat[i + NumStates] = mu_mat - sigma_root.col(i);
   }
 }
  void LangevinHullForceManager::postCalculation(){
  
    int nTriangles, thisFacet;
    RealType thisArea;
    vector<Triangle> sMesh;
    Triangle thisTriangle;
    vector<Triangle>::iterator face;
    vector<StuntDouble*> vertexSDs;
    vector<StuntDouble*>::iterator vertex;

    Vector3d unitNormal, centroid, facetVel;
    Vector3d langevinForce, vertexForce;
    Vector3d extPressure, randomForce, dragForce;

    Mat3x3d hydroTensor, S;
    vector<Vector3d> randNums;

    // Compute surface Mesh
    surfaceMesh_->computeHull(localSites_);
    // Get number of surface stunt doubles
    sMesh = surfaceMesh_->getMesh();
    nTriangles = sMesh.size();

    if (doThermalCoupling_) {
      // Generate all of the necessary random forces
      randNums = genTriangleForces(nTriangles, variance_);
    }
    
    // Loop over the mesh faces
    thisFacet = 0;
    for (face = sMesh.begin(); face != sMesh.end(); ++face){
      thisTriangle = *face;
      vertexSDs = thisTriangle.getVertices();
      thisArea = thisTriangle.getArea(); 
      unitNormal = thisTriangle.getUnitNormal();
      centroid = thisTriangle.getCentroid();
      facetVel = thisTriangle.getFacetVelocity();

      langevinForce = V3Zero;

      if (doPressureCoupling_) {
        extPressure = -unitNormal * (targetPressure_ * thisArea) /
          PhysicalConstants::energyConvert;
        langevinForce += extPressure;
      }

      if (doThermalCoupling_) {
        hydroTensor = thisTriangle.computeHydrodynamicTensor(viscosity_);      
        hydroTensor *= PhysicalConstants::viscoConvert;
        CholeskyDecomposition(hydroTensor, S);
        randomForce = S * randNums[thisFacet++];
        dragForce = -hydroTensor * facetVel;
        langevinForce += randomForce + dragForce;
      }
      
      // Apply triangle force to stuntdouble vertices
      for (vertex = vertexSDs.begin(); vertex != vertexSDs.end(); ++vertex){
	if ((*vertex) != NULL){
          vertexForce = langevinForce / RealType(3.0);
	  (*vertex)->addFrc(vertexForce);	   
	}  
      }
    } 
    
    veloMunge->removeComDrift();
    veloMunge->removeAngularDrift();
    
    Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
    currSnapshot->setVolume(surfaceMesh_->getVolume());   
    currSnapshot->setHullVolume(surfaceMesh_->getVolume());
    ForceManager::postCalculation();   
  }