void wendy_GIO_ROP::save_mata_ass(string arDsoPath,string dpCachePath,GU_Detail *gdp )
{
    //get arnold dso path


    g_particle_mataAss assROP;
    ofstream fout;
    string getCacheDP=dpCachePath;

    stringstream ss(getCacheDP);
    string sub_str;
    vector <string> sp_strPath;
    sp_strPath.clear();
    while(getline(ss,sub_str,'.'))
    {
        sp_strPath.push_back(sub_str);
    }

    string newAssPathName = sp_strPath[0]+"."+sp_strPath[1]+string(".ass");
    fout.open(newAssPathName);
    assROP.setGioCachePath(getCacheDP);  // set Link GIO CACHE
    for (GA_AttributeDict::iterator it = gdp->getAttributeDict(GA_ATTRIB_POINT).begin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it)
    {
        GA_Attribute *attrib = it.attrib();
        string attName( attrib->getName() );
        assROP.inserExtraMataInfo(attName);
    }
    //set ass bbox
    UT_BoundingBox BBOX;
    gdp->getBBox(&BBOX);
    BBOX.expandBounds(2,2,2);
    float min_x=BBOX.xmin();
    float min_y=BBOX.xmin();
    float min_z=BBOX.xmin();
    float max_x=BBOX.xmax();
    float max_y=BBOX.ymax();
    float max_z=BBOX.zmax();
    assROP.setBBOX(min_x,min_y,min_z,max_x,max_y,max_z);
    assROP.setDsoPath(arDsoPath);
    assROP.save(fout);
    fout.close();
}
static void updateAttributeList(g_global_io &io,GU_Detail *cur_gdp)
{
    fpreal numPt= cur_gdp->getNumPoints();
    GA_Iterator iter(cur_gdp->getPointRange());
    fpreal start_point_num = *iter;

    if ( cur_gdp )
    {
        for (GA_AttributeDict::iterator it = cur_gdp->getAttributeDict(GA_ATTRIB_POINT).begin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it)
        {
            GA_Attribute *attrib = it.attrib();
            UT_String attName( attrib->getName() );
            // std::cout<<"the att name is"<<attName<<std::endl;
            int attSize = attrib->getTupleSize();
            GA_StorageClass     storage= attrib->getStorageClass();
            GA_TypeInfo typeInfo = attrib->getTypeInfo();

            //save mata info



            switch(attSize)
            {
            case 1:                    // per  int or float
                if(storage==GA_STORECLASS_FLOAT)
                {
                    std::cout<<"the att name is "<<attName<< " and the type is float\n";
                    g_particles_io t_io;
                    t_io.GIO_SetCurrentAttributeName(attName);
                    t_io.GIO_SetCurrentAttributeType(g_particles_io::FLT_TYPE);
                    std::vector<float> t_value;  // create empty stack
                    forkTheFLTData(t_value,attrib,numPt,start_point_num);
                    t_io.GIO_setFLTAttributeList(t_value);
                    io.GIO_installParticleHandle(t_io);  // install this attribute into our global IO

                }
                if(storage==GA_STORECLASS_INT)
                {
                    std::cout<<"the att name is "<<attName<< " and the type is int\n";
                    g_particles_io t_io;
                    t_io.GIO_SetCurrentAttributeName(attName);
                    t_io.GIO_SetCurrentAttributeType(g_particles_io::INT_TYPE);
                    std::vector<int> t_value;  // create empty  int stack
                    forkTheINTData(t_value,attrib,numPt,start_point_num);
                    t_io.GIO_setINTAttributeList(t_value);
                    io.GIO_installParticleHandle(t_io);
                }
                break;
            case 3:                   // int vector or float vector
                if(storage==GA_STORECLASS_FLOAT)
                {
                    std::cout<<"the att name is "<<attName<< " and the type is float vector\n";
                    g_particles_io t_io;
                    t_io.GIO_SetCurrentAttributeName(attName);
                    t_io.GIO_SetCurrentAttributeType(g_particles_io::FLT_VEC_TYPE);
                    std::vector<per_float_vector> t_value;  // create empty  int stack
                    forkTheFLTVectorData(t_value,attrib,numPt,start_point_num);
                    t_io.GIO_setFLTVecAttributeList(t_value);
                    io.GIO_installParticleHandle(t_io);

                }
                if(storage==GA_STORECLASS_INT)
                {
                    std::cout<<"the att name is "<<attName<< " and the type is int vector\n";
                    g_particles_io t_io;
                    t_io.GIO_SetCurrentAttributeName(attName);
                    t_io.GIO_SetCurrentAttributeType(g_particles_io::INT_VEC_TYPE);
                    std::vector<per_int_vector> t_value;  // create empty  int stack
                    forkTheINTVectorData(t_value,attrib,numPt,start_point_num);
                    t_io.GIO_setINTVecAttributeList(t_value);
                    io.GIO_installParticleHandle(t_io);
                }
                break;
            case 4:                   // P attrib
            {
                std::cout<<"the att name is "<<attName<< " and the type is float 4 \n";
                g_particles_io t_io;
                t_io.GIO_SetCurrentAttributeName(attName);
                t_io.GIO_SetCurrentAttributeType(g_particles_io::FLT_VEC_TYPE);
                std::vector<per_float_vector> t_value;  // create empty  int stack
                forkTheFLTVectorData(t_value,it.attrib(),numPt,start_point_num);

                t_io.GIO_setFLTVecAttributeList(t_value);
                io.GIO_installParticleHandle(t_io);
            }

            break;
            }

        }
    }
}
static void exportParticlesDetail( const GU_Detail* gdp,
                                  const std::string& filePath,
                                  const std::map<std::string,
                                  channel_type>& desiredChannels )
{
	prt_ofstream ostream;

	static std::map<std::string, std::string> s_reservedChannels;
	if( s_reservedChannels.empty() ) {
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_NORMAL ) ] = "Normal";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_TEXTURE ) ] = "TextureCoord";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_VELOCITY ) ] = "Velocity";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_DIFFUSE ) ] = "Color";
		//s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ALPHA ) ] = "Density";
		//s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_MASS ) ] = "Density";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) ] = "";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ID ) ] = "ID";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_PSCALE ) ] = "Scale";
		s_reservedChannels[ "accel" ] = "Acceleration";
	}

	float posVal[3];
	float lifeVal[2];
	
	ostream.bind( "Position", posVal, 3 );

	//We handle the life channel in a special manner
	GA_ROAttributeRef lifeAttrib = gdp->findPointAttribute( gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) );
	if( lifeAttrib.isValid() ){
		std::map<std::string,channel_type>::const_iterator it;
		
		it = desiredChannels.find( "Age" );
		if( it != desiredChannels.end() && it->second.second == 1 )
			ostream.bind( "Age", &lifeVal[0], 1, it->second.first );
		else if( desiredChannels.empty() )
			ostream.bind( "Age", &lifeVal[0], 1, prtio::data_types::type_float16 );

		it = desiredChannels.find( "LifeSpan" );
		if( it != desiredChannels.end() && it->second.second == 1 )
			ostream.bind( "LifeSpan", &lifeVal[1], 1, it->second.first );
		else if( desiredChannels.empty() )
			ostream.bind( "LifeSpan", &lifeVal[1], 1, prtio::data_types::type_float16 );
	}
	
	//Using a deque to prevent the memory from moving around after adding the bound_attribute to the container.
	std::deque< bound_attribute<int> > m_intAttrs;
	std::deque< bound_attribute<float> > m_floatAttrs;
	std::deque< bound_attribute<float> > m_vectorAttrs;
	
	for ( GA_AttributeDict::iterator it = gdp->getAttributes().getDict(GA_ATTRIB_POINT).begin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it) {
		
		GA_Attribute *node = it.attrib();

		std::string channelName = node->getName();

		//Translate special names
		std::map<std::string,std::string>::const_iterator itResChannel = s_reservedChannels.find( channelName );
		if( itResChannel != s_reservedChannels.end() ){
			//If its empty, that means we reserve some sort of special handling.
			if( itResChannel->second.empty() )
				continue;
			channelName = itResChannel->second;
		}
		
		//Skip channels that aren't on the list.
		std::map<std::string,channel_type>::const_iterator itChannel = desiredChannels.find( channelName );
		bool channelIsDesired = ( itChannel != desiredChannels.end() );
		
		if( !desiredChannels.empty() && !channelIsDesired )
			continue;
			
		prtio::data_types::enum_t type;
		
		//Only add valid channel names
		if( detail::is_valid_channel_name( channelName.c_str() ) ) {
			//I add the new item to the deque, THEN initialize it since a deque will not move the object around and this allows
			//me to allocate the float array and not have to worry about the object getting deleted too early.
			switch( node->getStorageClass() ){
			case GA_STORECLASS_FLOAT:
				if( node->getTupleSize()==3 ){
					m_vectorAttrs.push_back( bound_attribute<float>() );
					m_vectorAttrs.back().attr =	gdp->findPointAttribute(node->getName());
					m_vectorAttrs.back().count = node->getTupleSize();
					m_vectorAttrs.back().data = new float[m_vectorAttrs.back().count];

					type = prtio::data_types::type_float16;
					if( channelIsDesired ){
						type = itChannel->second.first;
						if( itChannel->second.second != m_vectorAttrs.back().count )
							continue;
					}

					ostream.bind( channelName, m_vectorAttrs.back().data, m_vectorAttrs.back().count, type );

				} else {
					m_floatAttrs.push_back( bound_attribute<float>() );
					m_floatAttrs.back().attr =	gdp->findPointAttribute( node->getName() );
					m_floatAttrs.back().count = node->getTupleSize();
					m_floatAttrs.back().data = new float[m_floatAttrs.back().count];

					type = prtio::data_types::type_float16;
					if( channelIsDesired ){
						type = itChannel->second.first;
						if( itChannel->second.second != m_floatAttrs.back().count )
							continue;
					}

					ostream.bind( channelName, m_floatAttrs.back().data, m_floatAttrs.back().count, type );
				}
				break;
			case GA_STORECLASS_INT:
				m_intAttrs.push_back( bound_attribute<int>() );
				m_intAttrs.back().attr = gdp->findPointAttribute( node->getName() );
				m_intAttrs.back().count = node->getTupleSize();
				m_intAttrs.back().data = new int[m_intAttrs.back().count];

				type = prtio::data_types::type_int32;
				if( channelIsDesired ){
					type = itChannel->second.first;
					if( itChannel->second.second != m_intAttrs.back().count )
						continue;
				}
			
				ostream.bind( channelName, m_intAttrs.back().data, m_intAttrs.back().count, type );
				break;
			default:
				break;
			}
		}
	}

	try{
		ostream.open( filePath );
	} catch( const std::ios::failure& e ) {
		std::cerr << e.what() << std::endl;
		throw HOM_OperationFailed( "Failed to open the file" );
	}
		
	GA_IndexMap map = gdp->getPointMap();
	UT_Vector3 p;
	GEO_Point* pt;
	GA_Index indexSize = map.indexSize();
	GA_Offset offset;

	for( int i = 0 ; i < indexSize; i++ ) {
		offset = map.offsetFromIndex( i );
		p = gdp->getPos3( offset );
		posVal[0] = p.x();
		posVal[1] = p.y();
		posVal[2] = -1 * p.z();
		
		//TODO: Remove the GEO_Point object that is now deprecated. 
		pt = ( GEO_Point* )gdp->getGBPoint( offset );
		
		//TODO: Convert this into appropriate time values. Is it seconds or frames or what?!
		if( lifeAttrib.isValid() ) 
			pt->get( lifeAttrib, lifeVal, 2 );

		for( std::deque< bound_attribute<float> >::iterator it = m_floatAttrs.begin(), itEnd = m_floatAttrs.end(); it != itEnd; ++it )
			pt->get( it->attr, it->data, it->count );

		for( std::deque< bound_attribute<float> >::iterator it = m_vectorAttrs.begin(), itEnd = m_vectorAttrs.end(); it != itEnd; ++it ) {
			pt->get( it->attr, it->data, it->count );
				
			//TODO: Optionally transform into some consistent world space for PRT files.
		}

		for( std::deque< bound_attribute<int> >::iterator it = m_intAttrs.begin(), itEnd = m_intAttrs.end(); it != itEnd; ++it )
			pt->get( it->attr, it->data, it->count );

		ostream.write_next_particle();
	}
	
	ostream.close();
}