Example #1
0
void split(Side_List **sideListH, long nodeNum)
{
    // **sideListH;				 Listing of the sides in the domain for splitting DAG tree
    // nodeNum;						 The index for the segment from sideList to use for pivot/split in DAG tree
    long numSidesL =0;							// the number of sides that are split off to the left
    long numSidesR =0;							// the number of sides that are split off to the right
    Side_List **sidesLeftH = nil;				// pointer to area of heap where sides are left
    Side_List **sidesRightH = nil;				// pointer to area of hear where sides are left
    long numSideInList = _GetHandleSize((Handle)sideListH)/(sizeof(Side_List));	// The number of sides for splitting
    long location,i;
    long nodeP1,nodeP2;
    Side_List sideListForNode;
    long bCounterL =0, bCounterR =0;					// counting the number of boundary seg in a side list
    long branchNum;
    static long nsx = 0;

    nsx++;
    if(nsx == 964)
    {
        nsx = 0;
    }

    if(gErrStr[0] ) goto done;
    if(sideListH == nil)
    {
        strcpy(gErrStr,"Nil handle passed to split");
        goto done;
    }

    branchNum = gDagTree.numBranches;
    IncrementGDagTree();

    (*gDagTree.treeHdl)[branchNum].topoIndex = oldNodeNum(((*sideListH)[nodeNum]).p1,((*sideListH)[nodeNum]).p2);

    sidesLeftH = (Side_List **)_NewHandleClear((numSideInList)*sizeof(Side_List));
    if(!sidesLeftH) {
        strcpy(gErrStr,"Out of memory in split");
        goto done;
    }

    sidesRightH = (Side_List **)_NewHandleClear((numSideInList)*sizeof(Side_List));
    if(!sidesRightH) {
        strcpy(gErrStr,"Out of memory in split");
        goto done;
    }

    // find the node's points for determining relative right and left
    nodeP1 = (*sideListH)[nodeNum].p1;
    nodeP2 = (*sideListH)[nodeNum].p2;

    // Do the actual splitting
    for (i=0; i<numSideInList; i++) {
        if(i == nodeNum) continue; // skip the case that nodeNum = i

        // find the points associated with the test side
        location = Right_or_Left(nodeP1,nodeP2,(*sideListH)[i].p1,(*sideListH)[i].p2);

        // Distribute the sides to the two R/L areas of the heap
        switch(location)
        {
        case -1:// left
            (*sidesLeftH)[numSidesL++] = (*sideListH)[i];// copy the structure
            break;
        case 1: // right
            (*sidesRightH)[numSidesR++] = (*sideListH)[i];// copy the structure
            break;
        case 0: // both
            (*sidesLeftH)[numSidesL++] = (*sideListH)[i];// copy the structure
            (*sidesRightH)[numSidesR++] = (*sideListH)[i];// copy the structure
            break;
        }
    }


// trim sidesL and sidesR to numSidesL and numSidesR, respectively
    _SetHandleSize((Handle)sidesLeftH,(numSidesL)*sizeof(Side_List));
    _SetHandleSize((Handle)sidesRightH,(numSidesR)*sizeof(Side_List));

    sideListForNode = (*sideListH)[nodeNum];

    // Left Hand Side
    if (numSidesL ==0) {
        (*gDagTree.treeHdl)[branchNum].branchLeft = -8;
        // Fake a split
        if (sideListForNode.triLeft == -1)
        {
            strcpy(gErrStr,"Boundary not set up correctly - outside is on LHS");
            goto done;
        }

    }
    else {
        // fTreeH in GNOME (a DAGHdl), member of fDagTree (part of GridVel, owned by the mover)
        (*gDagTree.treeHdl)[branchNum].branchLeft = gDagTree.numBranches;
        if(gErrStr[0]) goto done;
        // set call for correct area for sides
        nodeNum = newNodexx(sidesLeftH);
        MySpinCursor(); // JLM 8/4/99
        split(sidesLeftH,nodeNum); 			// recursively for LHS
        //sidesLeftH = nil; // split disposed of this hdl
    }


    // Right Hand Side
    if (numSidesR == 0)
    {
        // Fake a split
        (*gDagTree.treeHdl)[branchNum].branchRight = -8;  // place holder for steps in dag to all tri
    }
    else
    {
        (*gDagTree.treeHdl)[branchNum].branchRight = gDagTree.numBranches;
        if(gErrStr[0]) goto done;
        // set call for correct area for sides
        nodeNum = newNodexx(sidesRightH);
        split(sidesRightH,nodeNum); 			// recursively for RHS
        //sidesRightH = nil; // split disposed of this hdl
    }

done:

    if(sidesRightH) DisposeHandle((Handle) sidesRightH);
    sidesRightH = nil;
    if(sidesLeftH) DisposeHandle((Handle) sidesLeftH);
    sidesLeftH = nil;

    return;
}
Example #2
0
OSErr ReadObjectInfo (short FRefNum, ObjectRecHdl *thisObjectHdlPtr)
{
	OSErr	ErrCode = 0;
	long	byteCount, structSize;
	Handle	thisObjectHdl = nil, thisObjectDataHdl = nil;

	// read the size of this object's info handle
	byteCount = sizeof (long);
	ErrCode = FSRead (FRefNum, &byteCount, (Ptr) &structSize);
	if (!ErrCode)
	{
		thisObjectHdl = _NewHandleClear (structSize);
		if (thisObjectHdl != nil)
		{
			_HLock (thisObjectHdl);
		
			ErrCode = FSRead (FRefNum, &structSize, (Ptr) *thisObjectHdl);
		
			_HUnlock (thisObjectHdl);
		}
		else
			ErrCode = memFullErr;
	}
	
	if (!ErrCode)	// read the object's data handle if any
	{
		if (GetObjectDataHdl ((ObjectRecHdl) thisObjectHdl) != nil)
		{
			// read the size of this object's data handle
			byteCount = sizeof (long);
			ErrCode = FSRead (FRefNum, &byteCount, (Ptr) &structSize);
		
			if (!ErrCode)
			{
				thisObjectDataHdl = _NewHandleClear (structSize);
				if (thisObjectDataHdl != nil)
				{
					_HLock (thisObjectDataHdl);
				
					ErrCode = FSRead (FRefNum, &structSize, (Ptr) *thisObjectDataHdl);

					_HUnlock (thisObjectDataHdl);

					if (!ErrCode)
						SetObjectDataHdl ((ObjectRecHdl) thisObjectHdl, thisObjectDataHdl);
				}
				else
					ErrCode = memFullErr;
			}
		}
	}
	
	if (ErrCode)
	{
		if (thisObjectHdl != nil)
			DisposeHandle (thisObjectDataHdl);	

		if (thisObjectHdl != nil)
			DisposeHandle (thisObjectDataHdl);	
	}
	
	if (!ErrCode)
		*thisObjectHdlPtr = (ObjectRecHdl) thisObjectHdl;	// send this handle back
	
	return (ErrCode);
}
Example #3
0
DAGTreeStruct  MakeDagTree(TopologyHdl topoHdl, LongPoint **pointList, char *errStr)
{
    Side_List **sidesList = 0;
    DAGTreeStruct  dagTree;
    long numSidesInList;
    long nodeNum;					// The index in the current side list for the node (segment)
    //			to split across.
    strcpy(errStr,"");
    dagTree.treeHdl = 0;
    dagTree.numBranches = 0;
    sidesList=BuildSideList(topoHdl, errStr);

    //input checking
    if(sidesList == nil)
    {
        strcpy(errStr,"sideList is nil in MakeDagTree");
        goto done;
    }

    LatLongTransform(pointList);
    gSidesList = sidesList;

    numSidesInList = (_GetHandleSize((Handle)sidesList))/(sizeof(Side_List));
    if (numSidesInList < 3)
    {
        sprintf(errStr,"Triangles have 3 sides; the data has only %ld sides.", numSidesInList);
        goto done;
    }

    // make a better guess of size here
    gErrStr[0] = 0;
    gAllocatedDagLength = 2*numSidesInList;

    gDagTree.numBranches=0;
    gDagTree.treeHdl = (DAG**)_NewHandleClear(gAllocatedDagLength*sizeof(DAG));
    if(!gDagTree.treeHdl)
    {
        strcpy(errStr,"Out of memory in MakeDagTree");
        goto done;
    }

    srand(SEED);
    //srand(SEED+1);

    nodeNum = newNodexx(sidesList);
    split(sidesList, nodeNum);
    //	Nothing should come back until DAG is completed.

    //gDagTree.numBranches--;  	// Had one too many increments in the split recursion.

    if(gErrStr[0])
    {
        strcpy(errStr,gErrStr);
        gErrStr[0] = 0;
        if(gDagTree.treeHdl) DisposeHandle((Handle) gDagTree.treeHdl);
        gDagTree.treeHdl = nil;
        gDagTree.numBranches = 0;
        goto done;
    }

    ConvertSegNoToTopIndex(sidesList,gDagTree);

    dagTree = gDagTree;
    gDagTree.treeHdl = nil;// the handle is now their responsibility
    gDagTree.numBranches = 0;

done:
    if(sidesList)
    {
        {
            DisposeHandle((Handle)sidesList);
            sidesList=0;
        }
    }
    return dagTree;
}
Example #4
0
OSErr NetCDFWindMoverCurv::ReadTimeData(long index,VelocityFH *velocityH, char* errmsg) 
{
	OSErr err = 0;
	long i,j;
	char path[256], outPath[256]; 
	char *velUnits=0;
	int status, ncid, numdims;
	int wind_ucmp_id, wind_vcmp_id, angle_id, uv_ndims;
	static size_t wind_index[] = {0,0,0,0}, angle_index[] = {0,0};
	static size_t wind_count[4], angle_count[2];
	size_t velunit_len;
	float *wind_uvals = 0,*wind_vvals = 0, fill_value=-1e-72, velConversion=1.;
	short *wind_uvals_Navy = 0,*wind_vvals_Navy = 0, fill_value_Navy;
	float *angle_vals = 0;
	long totalNumberOfVels = fNumRows * fNumCols;
	VelocityFH velH = 0;
	long latlength = fNumRows;
	long lonlength = fNumCols;
	float scale_factor = 1.,angle = 0.,u_grid,v_grid;
	Boolean bRotated = true, fIsNavy = false, bIsNWSSpeedDirData = false;
	
	errmsg[0]=0;
	
	strcpy(path,fPathName);
	if (!path || !path[0]) return -1;
	
	status = nc_open(path, NC_NOWRITE, &ncid);
	//if (status != NC_NOERR) {err = -1; goto done;}
	if (status != NC_NOERR)
	{
#if TARGET_API_MAC_CARBON
		err = ConvertTraditionalPathToUnixPath((const char *) path, outPath, kMaxNameLen) ;
		status = nc_open(outPath, NC_NOWRITE, &ncid);
#endif
		if (status != NC_NOERR) {err = -1; goto done;}
	}
	status = nc_inq_ndims(ncid, &numdims);
	if (status != NC_NOERR) {err = -1; goto done;}
	
	wind_index[0] = index;	// time 
	wind_count[0] = 1;	// take one at a time
	if (numdims>=4)	// should check what the dimensions are, CO-OPS uses sigma
	{
		wind_count[1] = 1;	// depth
		wind_count[2] = latlength;
		wind_count[3] = lonlength;
	}
	else
	{
		wind_count[1] = latlength;	
		wind_count[2] = lonlength;
	}
	angle_count[0] = latlength;
	angle_count[1] = lonlength;
	
	//wind_count[0] = latlength;		// a fudge for the PWS format which has u(lat,lon) not u(time,lat,lon)
	//wind_count[1] = lonlength;
	
	if (fIsNavy)
	{
		// need to check if type is float or short, if float no scale factor?
		wind_uvals = new float[latlength*lonlength]; 
		if(!wind_uvals) {TechError("GridVel::ReadNetCDFFile()", "new[]", 0); err = memFullErr; goto done;}
		wind_vvals = new float[latlength*lonlength]; 
		if(!wind_vvals) {TechError("GridVel::ReadNetCDFFile()", "new[]", 0); err = memFullErr; goto done;}
		
		angle_vals = new float[latlength*lonlength]; 
		if(!angle_vals) {TechError("GridVel::ReadNetCDFFile()", "new[]", 0); err = memFullErr; goto done;}
		status = nc_inq_varid(ncid, "air_gridu", &wind_ucmp_id);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_inq_varid(ncid, "air_gridv", &wind_vcmp_id);	
		if (status != NC_NOERR) {err = -1; goto done;}
		
		status = nc_get_vara_float(ncid, wind_ucmp_id, wind_index, wind_count, wind_uvals);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_get_vara_float(ncid, wind_vcmp_id, wind_index, wind_count, wind_vvals);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_get_att_float(ncid, wind_ucmp_id, "_FillValue", &fill_value);
		//if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_get_att_float(ncid, wind_ucmp_id, "scale_factor", &scale_factor);
		//if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_inq_varid(ncid, "grid_orient", &angle_id);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_get_vara_float(ncid, angle_id, angle_index, angle_count, angle_vals);
		if (status != NC_NOERR) {/*err = -1; goto done;*/bRotated = false;}
	}
	else
	{
		wind_uvals = new float[latlength*lonlength]; 
		if(!wind_uvals) {TechError("NetCDFWindMoverCurv::ReadTimeData()", "new[]", 0); err = memFullErr; goto done;}
		wind_vvals = new float[latlength*lonlength]; 
		if(!wind_vvals) {TechError("NetCDFWindMoverCurv::ReadTimeData()", "new[]", 0); err = memFullErr; goto done;}
		status = nc_inq_varid(ncid, "air_u", &wind_ucmp_id);
		if (status != NC_NOERR)
		{
			status = nc_inq_varid(ncid, "u", &wind_ucmp_id);
			if (status != NC_NOERR)
			{
				status = nc_inq_varid(ncid, "U", &wind_ucmp_id);
				if (status != NC_NOERR)
				{
					status = nc_inq_varid(ncid, "WindSpd_SFC", &wind_ucmp_id);
					if (status != NC_NOERR)
					{err = -1; goto done;}
					bIsNWSSpeedDirData = true;
				}
				//{err = -1; goto done;}
			}
			//{err = -1; goto done;}
		}
		if (bIsNWSSpeedDirData)
		{
			status = nc_inq_varid(ncid, "WindDir_SFC", &wind_vcmp_id);
			if (status != NC_NOERR)
			{err = -2; goto done;}
		}
		else
		{
			status = nc_inq_varid(ncid, "air_v", &wind_vcmp_id);
			if (status != NC_NOERR) 
			{
				status = nc_inq_varid(ncid, "v", &wind_vcmp_id);
				if (status != NC_NOERR) 
				{
					status = nc_inq_varid(ncid, "V", &wind_vcmp_id);
					if (status != NC_NOERR)
					{err = -1; goto done;}
				}
				//{err = -1; goto done;}
			}
		}
		
		status = nc_inq_varndims(ncid, wind_ucmp_id, &uv_ndims);
		if (status==NC_NOERR){if (uv_ndims < numdims && uv_ndims==3) {wind_count[1] = latlength; wind_count[2] = lonlength;}}	// could have more dimensions than are used in u,v
		
		status = nc_get_vara_float(ncid, wind_ucmp_id, wind_index, wind_count, wind_uvals);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_get_vara_float(ncid, wind_vcmp_id, wind_index, wind_count, wind_vvals);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_get_att_float(ncid, wind_ucmp_id, "_FillValue", &fill_value);
		if (status != NC_NOERR) 
		{
			status = nc_get_att_float(ncid, wind_ucmp_id, "Fill_Value", &fill_value);
			if (status != NC_NOERR)
			{
				status = nc_get_att_float(ncid, wind_ucmp_id, "fillValue", &fill_value);// nws 2.5km
				if (status != NC_NOERR)
				{
					status = nc_get_att_float(ncid, wind_ucmp_id, "missing_value", &fill_value);
				}
				/*if (status != NC_NOERR)*//*err = -1; goto done;*/}}	// don't require
		//if (status != NC_NOERR) {err = -1; goto done;}	// don't require
	}	
	
	status = nc_inq_attlen(ncid, wind_ucmp_id, "units", &velunit_len);
	if (status == NC_NOERR)
	{
		velUnits = new char[velunit_len+1];
		status = nc_get_att_text(ncid, wind_ucmp_id, "units", velUnits);
		if (status == NC_NOERR)
		{
			velUnits[velunit_len] = '\0'; 
			if (!strcmpnocase(velUnits,"knots"))
				velConversion = KNOTSTOMETERSPERSEC;
			else if (!strcmpnocase(velUnits,"m/s"))
				velConversion = 1.0;
		}
	}
	
	
	status = nc_close(ncid);
	if (status != NC_NOERR) {err = -1; goto done;}
	
	velH = (VelocityFH)_NewHandleClear(totalNumberOfVels * sizeof(VelocityFRec));
	if (!velH) {err = memFullErr; goto done;}
	//for (i=0;i<totalNumberOfVels;i++)
	for (i=0;i<latlength;i++)
	{
		for (j=0;j<lonlength;j++)
		{
			if (wind_uvals[(latlength-i-1)*lonlength+j]==fill_value)
				wind_uvals[(latlength-i-1)*lonlength+j]=0.;
			if (wind_vvals[(latlength-i-1)*lonlength+j]==fill_value)
				wind_vvals[(latlength-i-1)*lonlength+j]=0.;
			if (isnan(wind_uvals[(latlength-i-1)*lonlength+j])) 
				wind_uvals[(latlength-i-1)*lonlength+j]=0.;
			if (isnan(wind_vvals[(latlength-i-1)*lonlength+j])) 
				wind_vvals[(latlength-i-1)*lonlength+j]=0.;

			if (fIsNavy)
			{
				u_grid = (float)wind_uvals[(latlength-i-1)*lonlength+j];
				v_grid = (float)wind_vvals[(latlength-i-1)*lonlength+j];
				if (bRotated) angle = angle_vals[(latlength-i-1)*lonlength+j];
				INDEXH(velH,i*lonlength+j).u = u_grid*cos(angle*PI/180.)-v_grid*sin(angle*PI/180.);
				INDEXH(velH,i*lonlength+j).v = u_grid*sin(angle*PI/180.)+v_grid*cos(angle*PI/180.);
			}
			else if (bIsNWSSpeedDirData)
			{
				//INDEXH(velH,i*lonlength+j).u = KNOTSTOMETERSPERSEC * wind_uvals[(latlength-i-1)*lonlength+j] * sin ((PI/180.) * wind_vvals[(latlength-i-1)*lonlength+j]);	// need units
				//INDEXH(velH,i*lonlength+j).v = KNOTSTOMETERSPERSEC * wind_uvals[(latlength-i-1)*lonlength+j] * cos ((PI/180.) * wind_vvals[(latlength-i-1)*lonlength+j]);
				// since direction is from rather than to need to switch the sign
				//INDEXH(velH,i*lonlength+j).u = -1. * KNOTSTOMETERSPERSEC * wind_uvals[(latlength-i-1)*lonlength+j] * sin ((PI/180.) * wind_vvals[(latlength-i-1)*lonlength+j]);	// need units
				//INDEXH(velH,i*lonlength+j).v = -1. * KNOTSTOMETERSPERSEC * wind_uvals[(latlength-i-1)*lonlength+j] * cos ((PI/180.) * wind_vvals[(latlength-i-1)*lonlength+j]);
				INDEXH(velH,i*lonlength+j).u = -1. * velConversion * wind_uvals[(latlength-i-1)*lonlength+j] * sin ((PI/180.) * wind_vvals[(latlength-i-1)*lonlength+j]);	// need units
				INDEXH(velH,i*lonlength+j).v = -1. * velConversion * wind_uvals[(latlength-i-1)*lonlength+j] * cos ((PI/180.) * wind_vvals[(latlength-i-1)*lonlength+j]);
			}
			else
			{
				// Look for a land mask, but do this if don't find one - float mask(lat,lon) - 1,0 which is which?
				//if (wind_uvals[(latlength-i-1)*lonlength+j]==0. && wind_vvals[(latlength-i-1)*lonlength+j]==0.)
				//wind_uvals[(latlength-i-1)*lonlength+j] = wind_vvals[(latlength-i-1)*lonlength+j] = 1e-06;
				
				// just leave fillValue as velocity for new algorithm - comment following lines out
				// should eliminate the above problem, assuming fill_value is a land mask
				// leave for now since not using a map...use the entire grid
				/////////////////////////////////////////////////
				
				INDEXH(velH,i*lonlength+j).u = /*KNOTSTOMETERSPERSEC**/velConversion*wind_uvals[(latlength-i-1)*lonlength+j];	// need units
				INDEXH(velH,i*lonlength+j).v = /*KNOTSTOMETERSPERSEC**/velConversion*wind_vvals[(latlength-i-1)*lonlength+j];
			}
		}
	}
	*velocityH = velH;
	fFillValue = fill_value;
	
	fWindScale = scale_factor;	// hmm, this forces a reset of scale factor each time, overriding any set by hand
	
done:
	if (err)
	{
		if (err==-2)
			strcpy(errmsg,"Error reading wind data from NetCDF file");
		else
			strcpy(errmsg,"Error reading wind direction data from NetCDF file");
		// We don't want to put up an error message here because it can lead to an infinite loop of messages.
		//printNote("Error opening NetCDF file");
		if(velH) {DisposeHandle((Handle)velH); velH = 0;}
	}
	if (wind_uvals) {delete [] wind_uvals; wind_uvals = 0;}
	if (wind_vvals) {delete [] wind_vvals; wind_vvals = 0;}
	if (angle_vals) {delete [] angle_vals; angle_vals = 0;}
	return err;
}
Example #5
0
OSErr NetCDFWindMoverCurv::TextRead(char *path, TMap **newMap, char *topFilePath) // don't want a map  
{
	// this code is for curvilinear grids
	OSErr err = 0;
	long i,j, numScanned, indexOfStart = 0;
	int status, ncid, latIndexid, lonIndexid, latid, lonid, recid, timeid, numdims;
	size_t latLength, lonLength, recs, t_len, t_len2;
	float timeVal;
	char recname[NC_MAX_NAME], *timeUnits=0, month[10];	
	char dimname[NC_MAX_NAME], s[256], topPath[256];
	WORLDPOINTFH vertexPtsH=0;
	float *lat_vals=0,*lon_vals=0,yearShift=0.;
	static size_t timeIndex,ptIndex[2]={0,0};
	static size_t pt_count[2];
	Seconds startTime, startTime2;
	double timeConversion = 1.;
	char errmsg[256] = "",className[256]="";
	char fileName[64],*modelTypeStr=0;
	Point where;
	OSType typeList[] = { 'NULL', 'NULL', 'NULL', 'NULL' };
	MySFReply reply;
	Boolean bTopFile = false, fIsNavy = false;	// for now keep code around but probably don't need Navy curvilinear wind
	//VelocityFH velocityH = 0;
	char outPath[256];
	
	if (!path || !path[0]) return 0;
	strcpy(fPathName,path);
	
	strcpy(s,path);
	SplitPathFile (s, fileName);
	strcpy(fFileName, fileName); // maybe use a name from the file
	status = nc_open(path, NC_NOWRITE, &ncid);
	//if (status != NC_NOERR) {err = -1; goto done;}
	if (status != NC_NOERR) 
	{
#if TARGET_API_MAC_CARBON
		err = ConvertTraditionalPathToUnixPath((const char *) path, outPath, kMaxNameLen) ;
		status = nc_open(outPath, NC_NOWRITE, &ncid);
#endif
		if (status != NC_NOERR) {err = -1; goto done;}
	}
	// check number of dimensions - 2D or 3D
	status = nc_inq_ndims(ncid, &numdims);
	if (status != NC_NOERR) {err = -1; goto done;}
	
	status = nc_inq_attlen(ncid,NC_GLOBAL,"generating_model",&t_len2);
	if (status != NC_NOERR) {fIsNavy = false; /*goto done;*/}	
	else 
	{
		fIsNavy = true;
		// may only need to see keyword is there, since already checked grid type
		modelTypeStr = new char[t_len2+1];
		status = nc_get_att_text(ncid, NC_GLOBAL, "generating_model", modelTypeStr);
		if (status != NC_NOERR) {fIsNavy = false; goto done;}	
		modelTypeStr[t_len2] = '\0';
		
		strcpy(fFileName, modelTypeStr); 
	}
	GetClassName(className);
	if (!strcmp("NetCDF Wind",className))
		SetClassName(fFileName); //first check that name is now the default and not set by command file ("NetCDF Wind")
	
	//if (fIsNavy)
	{
		status = nc_inq_dimid(ncid, "time", &recid); //Navy
		//if (status != NC_NOERR) {err = -1; goto done;}
		if (status != NC_NOERR) 
		{	status = nc_inq_unlimdim(ncid, &recid);	// issue of time not being unlimited dimension
			if (status != NC_NOERR) {err = -1; goto done;}
		}			
	}
	/*else
	 {
	 status = nc_inq_unlimdim(ncid, &recid);	// issue of time not being unlimited dimension
	 if (status != NC_NOERR) {err = -1; goto done;}
	 }*/
	
	//if (fIsNavy)
	status = nc_inq_varid(ncid, "time", &timeid); 
	if (status != NC_NOERR) 
	{	
		status = nc_inq_varid(ncid, "ProjectionHr", &timeid); 
		if (status != NC_NOERR) {err = -1; goto done;}
	}			
	//	if (status != NC_NOERR) {/*err = -1; goto done;*/timeid=recid;} 
	
	//if (!fIsNavy)
	//status = nc_inq_attlen(ncid, recid, "units", &t_len);	// recid is the dimension id not the variable id
	//else	// LAS has them in order, and time is unlimited, but variable/dimension names keep changing so leave this way for now
	status = nc_inq_attlen(ncid, timeid, "units", &t_len);
	if (status != NC_NOERR) 
	{
		timeUnits = 0;	// files should always have this info
		timeConversion = 3600.;		// default is hours
		startTime2 = model->GetStartTime();	// default to model start time
		//err = -1; goto done;
	}
	else
	{
		DateTimeRec time;
		char unitStr[24], junk[10];
		
		timeUnits = new char[t_len+1];
		//if (!fIsNavy)
		//status = nc_get_att_text(ncid, recid, "units", timeUnits);	// recid is the dimension id not the variable id
		//else
		status = nc_get_att_text(ncid, timeid, "units", timeUnits);
		if (status != NC_NOERR) {err = -1; goto done;} 
		timeUnits[t_len] = '\0'; // moved this statement before StringSubstitute, JLM 5/2/10
		StringSubstitute(timeUnits, ':', ' ');
		StringSubstitute(timeUnits, '-', ' ');
		StringSubstitute(timeUnits, 'T', ' ');
		StringSubstitute(timeUnits, 'Z', ' ');
		
		numScanned=sscanf(timeUnits, "%s %s %hd %hd %hd %hd %hd %hd",
						  unitStr, junk, &time.year, &time.month, &time.day,
						  &time.hour, &time.minute, &time.second) ;
		if (numScanned==5)	
		{time.hour = 0; time.minute = 0; time.second = 0; }
		else if (numScanned==7) // has two extra time entries ??	
			time.second = 0;
		else if (numScanned<8)	
		//else if (numScanned!=8)	
		{ 
			//timeUnits = 0;	// files should always have this info
			//timeConversion = 3600.;		// default is hours
			//startTime2 = model->GetStartTime();	// default to model start time
			err = -1; TechError("NetCDFWindMoverCurv::TextRead()", "sscanf() == 8", 0); goto done;
		}
		else
		{
			// code goes here, trouble with the DAYS since 1900 format, since converts to seconds since 1904
			if (time.year ==1900) {time.year += 40; time.day += 1; /*for the 1900 non-leap yr issue*/ yearShift = 40.;}
			DateToSeconds (&time, &startTime2);	// code goes here, which start Time to use ??
			if (!strcmpnocase(unitStr,"HOURS") || !strcmpnocase(unitStr,"HOUR"))
				timeConversion = 3600.;
			else if (!strcmpnocase(unitStr,"MINUTES") || !strcmpnocase(unitStr,"MINUTE"))
				timeConversion = 60.;
			else if (!strcmpnocase(unitStr,"SECONDS") || !strcmpnocase(unitStr,"SECOND"))
				timeConversion = 1.;
			else if (!strcmpnocase(unitStr,"DAYS") || !strcmpnocase(unitStr,"DAY"))
				timeConversion = 24.*3600.;
		}
	} 
	
	status = nc_inq_dimid(ncid, "yc", &latIndexid); 
	if (status != NC_NOERR) 
	{	
		status = nc_inq_dimid(ncid, "y", &latIndexid); 
		if (status != NC_NOERR) 
		{
			err = -1; goto OLD;
		}
	}
	bIsCOOPSWaterMask = true;
	status = nc_inq_varid(ncid, "latc", &latid);
	if (status != NC_NOERR) 
	{
		status = nc_inq_varid(ncid, "lat", &latid);
		if (status != NC_NOERR) 
		{
			err = -1; goto done;
		}
	}
	status = nc_inq_dimlen(ncid, latIndexid, &latLength);
	if (status != NC_NOERR) {err = -1; goto done;}
	status = nc_inq_dimid(ncid, "xc", &lonIndexid);	
	if (status != NC_NOERR) 
	{
		status = nc_inq_dimid(ncid, "x", &lonIndexid); 
		if (status != NC_NOERR) 
		{
			err = -1; goto done;
		}
	}
	status = nc_inq_varid(ncid, "lonc", &lonid);	
	if (status != NC_NOERR) 
	{
		status = nc_inq_varid(ncid, "lon", &lonid);
		if (status != NC_NOERR) 
		{
			err = -1; goto done;
		}
	}
	status = nc_inq_dimlen(ncid, lonIndexid, &lonLength);
	if (status != NC_NOERR) {err = -1; goto done;}
	
OLD:
	if (!bIsCOOPSWaterMask)	
	{
	if (fIsNavy)
	{
		status = nc_inq_dimid(ncid, "gridy", &latIndexid); //Navy
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_inq_dimlen(ncid, latIndexid, &latLength);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_inq_dimid(ncid, "gridx", &lonIndexid);	//Navy
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_inq_dimlen(ncid, lonIndexid, &lonLength);
		if (status != NC_NOERR) {err = -1; goto done;}
		// option to use index values?
		status = nc_inq_varid(ncid, "grid_lat", &latid);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_inq_varid(ncid, "grid_lon", &lonid);
		if (status != NC_NOERR) {err = -1; goto done;}
	}
	else
	{
		for (i=0;i<numdims;i++)
		{
			if (i == recid) continue;
			status = nc_inq_dimname(ncid,i,dimname);
			if (status != NC_NOERR) {err = -1; goto done;}
			if (!strncmpnocase(dimname,"X",1) || !strncmpnocase(dimname,"LON",3) || !strncmpnocase(dimname,"nx",2))
			{
				lonIndexid = i;
			}
			if (!strncmpnocase(dimname,"Y",1) || !strncmpnocase(dimname,"LAT",3) || !strncmpnocase(dimname,"ny",2))
			{
				latIndexid = i;
			}
		}
		
		status = nc_inq_dimlen(ncid, latIndexid, &latLength);
		if (status != NC_NOERR) {err = -1; goto done;}
		status = nc_inq_dimlen(ncid, lonIndexid, &lonLength);
		if (status != NC_NOERR) {err = -1; goto done;}
		
		status = nc_inq_varid(ncid, "LATITUDE", &latid);
		if (status != NC_NOERR) 
		{
			status = nc_inq_varid(ncid, "lat", &latid);
			if (status != NC_NOERR) 
			{
				status = nc_inq_varid(ncid, "latitude", &latid);
				if (status != NC_NOERR) {err = -1; goto done;}
			}
		}
		status = nc_inq_varid(ncid, "LONGITUDE", &lonid);
		if (status != NC_NOERR) 
		{
			status = nc_inq_varid(ncid, "lon", &lonid);
			if (status != NC_NOERR) 
			{
				status = nc_inq_varid(ncid, "longitude", &lonid);
				if (status != NC_NOERR) {err = -1; goto done;}
			}
		}
	}
	}
	pt_count[0] = latLength;
	pt_count[1] = lonLength;
	vertexPtsH = (WorldPointF**)_NewHandleClear(latLength*lonLength*sizeof(WorldPointF));
	if (!vertexPtsH) {err = memFullErr; goto done;}
	lat_vals = new float[latLength*lonLength]; 
	lon_vals = new float[latLength*lonLength]; 
	if (!lat_vals || !lon_vals) {err = memFullErr; goto done;}
	status = nc_get_vara_float(ncid, latid, ptIndex, pt_count, lat_vals);
	if (status != NC_NOERR) {err = -1; goto done;}
	status = nc_get_vara_float(ncid, lonid, ptIndex, pt_count, lon_vals);
	if (status != NC_NOERR) {err = -1; goto done;}
	for (i=0;i<latLength;i++)
	{
		for (j=0;j<lonLength;j++)
		{
			//if (lat_vals[(latLength-i-1)*lonLength+j]==fill_value)	// this would be an error
			//lat_vals[(latLength-i-1)*lonLength+j]=0.;
			//if (lon_vals[(latLength-i-1)*lonLength+j]==fill_value)
			//lon_vals[(latLength-i-1)*lonLength+j]=0.;
			INDEXH(vertexPtsH,i*lonLength+j).pLat = lat_vals[(latLength-i-1)*lonLength+j];	
			INDEXH(vertexPtsH,i*lonLength+j).pLong = lon_vals[(latLength-i-1)*lonLength+j];
		}
	}
	fVertexPtsH	 = vertexPtsH;
	
	status = nc_inq_dim(ncid, recid, recname, &recs);
	if (status != NC_NOERR) {err = -1; goto done;}
	if (recs<=0) {strcpy(errmsg,"No times in file. Error opening NetCDF wind file"); err =  -1; goto done;}
	
	fTimeHdl = (Seconds**)_NewHandleClear(recs*sizeof(Seconds));
	if (!fTimeHdl) {err = memFullErr; goto done;}
	for (i=0;i<recs;i++)
	{
		Seconds newTime;
		// possible units are, HOURS, MINUTES, SECONDS,...
		timeIndex = i;
		//if (!fIsNavy)
		//status = nc_get_var1_float(ncid, recid, &timeIndex, &timeVal);	// recid is the dimension id not the variable id
		//else
		status = nc_get_var1_float(ncid, timeid, &timeIndex, &timeVal);
		if (status != NC_NOERR) {err = -1; goto done;}
		newTime = RoundDateSeconds(round(startTime2+timeVal*timeConversion));
		//INDEXH(fTimeHdl,i) = startTime2+(long)(timeVal*timeConversion -yearShift*3600.*24.*365.25);	// which start time where?
		//if (i==0) startTime = startTime2+(long)(timeVal*timeConversion -yearShift*3600.*24.*365.25);
		INDEXH(fTimeHdl,i) = newTime-yearShift*3600.*24.*365.25;	// which start time where?
		if (i==0) startTime = newTime-yearShift*3600.*24.*365.25;
	}
	if (model->GetStartTime() != startTime || model->GetModelTime()!=model->GetStartTime())
	{
		if (true)	// maybe use NOAA.ver here?
		{
			short buttonSelected;
			//buttonSelected  = MULTICHOICEALERT(1688,"Do you want to reset the model start time to the first time in the file?",FALSE);
			if(!gCommandFileRun)	// also may want to skip for location files...
				buttonSelected  = MULTICHOICEALERT(1688,"Do you want to reset the model start time to the first time in the file?",FALSE);
			else buttonSelected = 1;	// TAP user doesn't want to see any dialogs, always reset (or maybe never reset? or send message to errorlog?)
			switch(buttonSelected){
				case 1: // reset model start time
					//bTopFile = true;
					model->SetModelTime(startTime);
					model->SetStartTime(startTime);
					model->NewDirtNotification(DIRTY_RUNBAR); // must reset the runbar
					break;  
				case 3: // don't reset model start time
					//bTopFile = false;
					break;
				case 4: // cancel
					err=-1;// user cancel
					goto done;
			}
		}
		//model->SetModelTime(startTime);
		//model->SetStartTime(startTime);
		//model->NewDirtNotification(DIRTY_RUNBAR); // must reset the runbar
	}
	
	fNumRows = latLength;
	fNumCols = lonLength;
	
	status = nc_close(ncid);
	if (status != NC_NOERR) {err = -1; goto done;}
	
	//err = this -> SetInterval(errmsg);
	//if(err) goto done;
	
	// look for topology in the file
	// for now ask for an ascii file, output from Topology save option
	// need dialog to ask for file
	//if (fIsNavy)	// for now don't allow for wind files
	{if (topFilePath[0]) {err = ReadTopology(topFilePath,newMap); goto done;}}
	if (!gCommandFileRun)
	{
		short buttonSelected;
		buttonSelected  = MULTICHOICEALERT(1688,"Do you have an extended topology file to load?",FALSE);
		switch(buttonSelected){
			case 1: // there is an extended top file
				bTopFile = true;
				break;  
			case 3: // no extended top file
				bTopFile = false;
				break;
			case 4: // cancel
				err=-1;// stay at this dialog
				goto done;
		}
	}
	if(bTopFile)
	{
#if TARGET_API_MAC_CARBON
		mysfpgetfile(&where, "", -1, typeList,
					 (MyDlgHookUPP)0, &reply, M38c, MakeModalFilterUPP(STDFilter));
		if (!reply.good)/* return USERCANCEL;*/
		{
			/*if (recs>0)
				err = this -> ReadTimeData(indexOfStart,&velocityH,errmsg);
			else {strcpy(errmsg,"No times in file. Error opening NetCDF file"); err =  -1;}
			if(err) goto done;*/
			if (bIsCOOPSWaterMask) err = dynamic_cast<NetCDFWindMoverCurv *>(this)->ReorderPointsCOOPSNoMask(newMap,errmsg);	
			else err = dynamic_cast<NetCDFWindMoverCurv *>(this)->ReorderPoints(newMap,errmsg);	
			//err = ReorderPoints(fStartData.dataHdl,newMap,errmsg);	// if u, v input separately only do this once?
	 		goto done;
		}
		else
			strcpy(topPath, reply.fullPath);
		
#else
		where = CenteredDialogUpLeft(M38c);
		sfpgetfile(&where, "",
				   (FileFilterUPP)0,
				   -1, typeList,
				   (DlgHookUPP)0,
				   &reply, M38c,
				   (ModalFilterUPP)MakeUPP((ProcPtr)STDFilter, uppModalFilterProcInfo));
		if (!reply.good) 
		{
			/*if (recs>0)
				err = this -> ReadTimeData(indexOfStart,&velocityH,errmsg);
			else {strcpy(errmsg,"No times in file. Error opening NetCDF file"); err =  -1;}
			if(err) goto done;*/
			if (bIsCOOPSWaterMask) err = dynamic_cast<NetCDFWindMoverCurv *>(this)->ReorderPointsCOOPSNoMask(newMap,errmsg);	
			else err = dynamic_cast<NetCDFWindMoverCurv *>(this)->ReorderPoints(newMap,errmsg);	
			//err = ReorderPoints(fStartData.dataHdl,newMap,errmsg);	
	 		/*if (err)*/ goto done;
		}
		
		my_p2cstr(reply.fName);
		
#ifdef MAC
		GetFullPath(reply.vRefNum, 0, (char *)reply.fName, topPath);
#else
		strcpy(topPath, reply.fName);
#endif
#endif		
		strcpy (s, topPath);
		err = ReadTopology(topPath,newMap);	
		goto done;
	}
	
	/*if (recs>0)
		err = this -> ReadTimeData(indexOfStart,&velocityH,errmsg);
	else {strcpy(errmsg,"No times in file. Error opening NetCDF wind file"); err =  -1;}
	if(err) goto done;*/
	if (bIsCOOPSWaterMask) err = dynamic_cast<NetCDFWindMoverCurv *>(this)->ReorderPointsCOOPSNoMask(newMap,errmsg);	
	else err = dynamic_cast<NetCDFWindMoverCurv *>(this)->ReorderPoints(newMap,errmsg);	
	//err = ReorderPoints(fStartData.dataHdl,newMap,errmsg);	
	
done:
	if (err)
	{
		printNote("Error opening NetCDF wind file");
		if(fGrid)
		{
			fGrid ->Dispose();
			delete fGrid;
			fGrid = 0;
		}
		if(vertexPtsH) {DisposeHandle((Handle)vertexPtsH); vertexPtsH = 0;	fVertexPtsH	 = 0;}
	}
	
	if (timeUnits) delete [] timeUnits;
	if (lat_vals) delete [] lat_vals;
	if (lon_vals) delete [] lon_vals;
	if (modelTypeStr) delete [] modelTypeStr;
	//if (velocityH) {DisposeHandle((Handle)velocityH); velocityH = 0;}
	return err;
}
// simplify for wind data - no map needed, no mask 
OSErr NetCDFWindMoverCurv_c::ReorderPoints(TMap **newMap, char* errmsg) 
{
	long i, j, n, ntri, numVerdatPts=0;
	long fNumRows_ext = fNumRows+1, fNumCols_ext = fNumCols+1;
	long nv = fNumRows * fNumCols, nv_ext = fNumRows_ext*fNumCols_ext;
	long iIndex, jIndex, index; 
	long triIndex1, triIndex2, waterCellNum=0;
	long ptIndex = 0, cellNum = 0;
	long indexOfStart = 0;
	OSErr err = 0;
	
	LONGH landWaterInfo = (LONGH)_NewHandleClear(fNumRows * fNumCols * sizeof(long));
	LONGH maskH2 = (LONGH)_NewHandleClear(nv_ext * sizeof(long));
	
	LONGH ptIndexHdl = (LONGH)_NewHandleClear(nv_ext * sizeof(**ptIndexHdl));
	LONGH verdatPtsH = (LONGH)_NewHandleClear(nv_ext * sizeof(**verdatPtsH));
	GridCellInfoHdl gridCellInfo = (GridCellInfoHdl)_NewHandleClear(nv * sizeof(**gridCellInfo));
	
	TopologyHdl topo=0;
	LongPointHdl pts=0;
	VelocityFH velH = 0;
	DAGTreeStruct tree;
	WorldRect triBounds;
	
	TTriGridVel *triGrid = nil;
	tree.treeHdl = 0;
	TDagTree *dagTree = 0;
	
	VelocityFH velocityH = 0;
	
	if (!landWaterInfo || !ptIndexHdl || !gridCellInfo || !verdatPtsH || !maskH2) {err = memFullErr; goto done;}
	
	err = ReadTimeData(indexOfStart,&velocityH,errmsg);	// try to use velocities to set grid
	
	for (i=0;i<fNumRows;i++)
	{
		for (j=0;j<fNumCols;j++)
		{
			// eventually will need to have a land mask, for now assume fillValue represents land
			//if (INDEXH(velocityH,i*fNumCols+j).u==0 && INDEXH(velocityH,i*fNumCols+j).v==0)	// land point
			if (INDEXH(velocityH,i*fNumCols+j).u==fFillValue && INDEXH(velocityH,i*fNumCols+j).v==fFillValue)	// land point
			{
				INDEXH(landWaterInfo,i*fNumCols+j) = -1;	// may want to mark each separate island with a unique number
			}
			else
			{
				INDEXH(landWaterInfo,i*fNumCols+j) = 1;
				INDEXH(ptIndexHdl,i*fNumCols_ext+j) = -2;	// water box
				INDEXH(ptIndexHdl,i*fNumCols_ext+j+1) = -2;
				INDEXH(ptIndexHdl,(i+1)*fNumCols_ext+j) = -2;
				INDEXH(ptIndexHdl,(i+1)*fNumCols_ext+j+1) = -2;
			}
		}
	}
	
	for (i=0;i<fNumRows_ext;i++)
	{
		for (j=0;j<fNumCols_ext;j++)
		{
			if (INDEXH(ptIndexHdl,i*fNumCols_ext+j) == -2)
			{
				INDEXH(ptIndexHdl,i*fNumCols_ext+j) = ptIndex;	// count up grid points
				ptIndex++;
			}
			else
				INDEXH(ptIndexHdl,i*fNumCols_ext+j) = -1;
		}
	}
	
	for (i=0;i<fNumRows;i++)
	{
		for (j=0;j<fNumCols;j++)
		{
			if (INDEXH(landWaterInfo,i*fNumCols+j)>0)
			{
				INDEXH(gridCellInfo,i*fNumCols+j).cellNum = cellNum;
				cellNum++;
				INDEXH(gridCellInfo,i*fNumCols+j).topLeft = INDEXH(ptIndexHdl,i*fNumCols_ext+j);
				INDEXH(gridCellInfo,i*fNumCols+j).topRight = INDEXH(ptIndexHdl,i*fNumCols_ext+j+1);
				INDEXH(gridCellInfo,i*fNumCols+j).bottomLeft = INDEXH(ptIndexHdl,(i+1)*fNumCols_ext+j);
				INDEXH(gridCellInfo,i*fNumCols+j).bottomRight = INDEXH(ptIndexHdl,(i+1)*fNumCols_ext+j+1);
			}
			else INDEXH(gridCellInfo,i*fNumCols+j).cellNum = -1;
		}
	}
	ntri = cellNum*2;	// each water cell is split into two triangles
	if(!(topo = (TopologyHdl)_NewHandleClear(ntri * sizeof(Topology)))){err = memFullErr; goto done;}	
	for (i=0;i<nv_ext;i++)
	{
		if (INDEXH(ptIndexHdl,i) != -1)
		{
			INDEXH(verdatPtsH,numVerdatPts) = i;
			//INDEXH(verdatPtsH,INDEXH(ptIndexHdl,i)) = i;
			numVerdatPts++;
		}
	}
	_SetHandleSize((Handle)verdatPtsH,numVerdatPts*sizeof(**verdatPtsH));
	pts = (LongPointHdl)_NewHandle(sizeof(LongPoint)*(numVerdatPts));
	if(pts == nil)
	{
		strcpy(errmsg,"Not enough memory to triangulate data.");
		return -1;
	}
	
	for (i=0; i<=numVerdatPts; i++)	// make a list of grid points that will be used for triangles
	{
		float fLong, fLat, fDepth, dLon, dLat, dLon1, dLon2, dLat1, dLat2;
		//double val, u=0., v=0.;
		LongPoint vertex;
		
		if(i < numVerdatPts) 
		{	// since velocities are defined at the lower left corner of each grid cell
			// need to add an extra row/col at the top/right of the grid
			// set lat/lon based on distance between previous two points 
			// these are just for boundary/drawing purposes, velocities are set to zero
			index = i+1;
			n = INDEXH(verdatPtsH,i);
			iIndex = n/fNumCols_ext;
			jIndex = n%fNumCols_ext;
			if (iIndex==0)
			{
				if (jIndex<fNumCols)
				{
					dLat = INDEXH(fVertexPtsH,fNumCols+jIndex).pLat - INDEXH(fVertexPtsH,jIndex).pLat;
					fLat = INDEXH(fVertexPtsH,jIndex).pLat - dLat;
					dLon = INDEXH(fVertexPtsH,fNumCols+jIndex).pLong - INDEXH(fVertexPtsH,jIndex).pLong;
					fLong = INDEXH(fVertexPtsH,jIndex).pLong - dLon;
				}
				else
				{
					dLat1 = (INDEXH(fVertexPtsH,jIndex-1).pLat - INDEXH(fVertexPtsH,jIndex-2).pLat);
					dLat2 = INDEXH(fVertexPtsH,fNumCols+jIndex-1).pLat - INDEXH(fVertexPtsH,fNumCols+jIndex-2).pLat;
					fLat = 2*(INDEXH(fVertexPtsH,jIndex-1).pLat + dLat1)-(INDEXH(fVertexPtsH,fNumCols+jIndex-1).pLat+dLat2);
					dLon1 = INDEXH(fVertexPtsH,fNumCols+jIndex-1).pLong - INDEXH(fVertexPtsH,jIndex-1).pLong;
					dLon2 = (INDEXH(fVertexPtsH,fNumCols+jIndex-2).pLong - INDEXH(fVertexPtsH,jIndex-2).pLong);
					fLong = 2*(INDEXH(fVertexPtsH,jIndex-1).pLong-dLon1)-(INDEXH(fVertexPtsH,jIndex-2).pLong-dLon2);
				}
			}
			else 
			{
				if (jIndex<fNumCols)
				{
					fLat = INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex).pLat;
					fLong = INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex).pLong;
					//u = INDEXH(velocityH,(iIndex-1)*fNumCols+jIndex).u;
					//v = INDEXH(velocityH,(iIndex-1)*fNumCols+jIndex).v;
				}
				else
				{
					dLat = INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex-1).pLat - INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex-2).pLat;
					fLat = INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex-1).pLat + dLat;
					dLon = INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex-1).pLong - INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex-2).pLong;
					fLong = INDEXH(fVertexPtsH,(iIndex-1)*fNumCols+jIndex-1).pLong + dLon;
				}
			}
			vertex.v = (long)(fLat*1e6);
			vertex.h = (long)(fLong*1e6);
			
			fDepth = 1.;
			INDEXH(pts,i) = vertex;
		}
		else { // for outputting a verdat the last line should be all zeros
			index = 0;
			fLong = fLat = fDepth = 0.0;
		}
		/////////////////////////////////////////////////
		
	}
	// figure out the bounds
	triBounds = voidWorldRect;
	if(pts) 
	{
		LongPoint	thisLPoint;
		
		if(numVerdatPts > 0)
		{
			WorldPoint  wp;
			for(i=0;i<numVerdatPts;i++)
			{
				thisLPoint = INDEXH(pts,i);
				wp.pLat = thisLPoint.v;
				wp.pLong = thisLPoint.h;
				AddWPointToWRect(wp.pLat, wp.pLong, &triBounds);
			}
		}
	}
	
	DisplayMessage("NEXTMESSAGETEMP");
	DisplayMessage("Making Triangles");
	
	/////////////////////////////////////////////////
	for (i=0;i<fNumRows;i++)
	{
		for (j=0;j<fNumCols;j++)
		{
			if (INDEXH(landWaterInfo,i*fNumCols+j)==-1)
				continue;
			waterCellNum = INDEXH(gridCellInfo,i*fNumCols+j).cellNum;	// split each cell into 2 triangles
			triIndex1 = 2*waterCellNum;
			triIndex2 = 2*waterCellNum+1;
			// top/left tri in rect
			(*topo)[triIndex1].vertex1 = INDEXH(gridCellInfo,i*fNumCols+j).topRight;
			(*topo)[triIndex1].vertex2 = INDEXH(gridCellInfo,i*fNumCols+j).topLeft;
			(*topo)[triIndex1].vertex3 = INDEXH(gridCellInfo,i*fNumCols+j).bottomLeft;
			if (j==0 || INDEXH(gridCellInfo,i*fNumCols+j-1).cellNum == -1)
				(*topo)[triIndex1].adjTri1 = -1;
			else
			{
				(*topo)[triIndex1].adjTri1 = INDEXH(gridCellInfo,i*fNumCols+j-1).cellNum * 2 + 1;
			}
			(*topo)[triIndex1].adjTri2 = triIndex2;
			if (i==0 || INDEXH(gridCellInfo,(i-1)*fNumCols+j).cellNum==-1)
				(*topo)[triIndex1].adjTri3 = -1;
			else
			{
				(*topo)[triIndex1].adjTri3 = INDEXH(gridCellInfo,(i-1)*fNumCols+j).cellNum * 2 + 1;
			}
			// bottom/right tri in rect
			(*topo)[triIndex2].vertex1 = INDEXH(gridCellInfo,i*fNumCols+j).bottomLeft;
			(*topo)[triIndex2].vertex2 = INDEXH(gridCellInfo,i*fNumCols+j).bottomRight;
			(*topo)[triIndex2].vertex3 = INDEXH(gridCellInfo,i*fNumCols+j).topRight;
			if (j==fNumCols-1 || INDEXH(gridCellInfo,i*fNumCols+j+1).cellNum == -1)
				(*topo)[triIndex2].adjTri1 = -1;
			else
			{
				(*topo)[triIndex2].adjTri1 = INDEXH(gridCellInfo,i*fNumCols+j+1).cellNum * 2;
			}
			(*topo)[triIndex2].adjTri2 = triIndex1;
			if (i==fNumRows-1 || INDEXH(gridCellInfo,(i+1)*fNumCols+j).cellNum == -1)
				(*topo)[triIndex2].adjTri3 = -1;
			else
			{
				(*topo)[triIndex2].adjTri3 = INDEXH(gridCellInfo,(i+1)*fNumCols+j).cellNum * 2;
			}
		}
	}
	
	DisplayMessage("NEXTMESSAGETEMP");
	DisplayMessage("Making Dag Tree");
	MySpinCursor(); // JLM 8/4/99
	tree = MakeDagTree(topo, (LongPoint**)pts, errmsg); 
	MySpinCursor(); // JLM 8/4/99
	if (errmsg[0])	
	{err = -1; goto done;} 
	// sethandle size of the fTreeH to be tree.fNumBranches, the rest are zeros
	_SetHandleSize((Handle)tree.treeHdl,tree.numBranches*sizeof(DAG));
	/////////////////////////////////////////////////
	
	fVerdatToNetCDFH = verdatPtsH;
	
	/////////////////////////////////////////////////
	
	triGrid = new TTriGridVel;
	if (!triGrid)
	{		
		err = true;
		TechError("Error in NetCDFWindMoverCurv::ReorderPoints()","new TTriGridVel",err);
		goto done;
	}
	
	fGrid = (TTriGridVel*)triGrid;
	
	triGrid -> SetBounds(triBounds); 
	dagTree = new TDagTree(pts,topo,tree.treeHdl,velH,tree.numBranches); 
	if(!dagTree)
	{
		err = -1;
		printError("Unable to create dag tree.");
		goto done;
	}
	
	triGrid -> SetDagTree(dagTree);
	//triGrid -> SetDepths(totalDepthH);	// used by PtCurMap to check vertical movement
	
	pts = 0;	// because fGrid is now responsible for it
	topo = 0; // because fGrid is now responsible for it
	velH = 0; // because fGrid is now responsible for it
	tree.treeHdl = 0; // because fGrid is now responsible for it
	velH = 0; // because fGrid is now responsible for it
	
	/////////////////////////////////////////////////
done:
	if (landWaterInfo) {DisposeHandle((Handle)landWaterInfo); landWaterInfo=0;}
	if (ptIndexHdl) {DisposeHandle((Handle)ptIndexHdl); ptIndexHdl = 0;}
	if (gridCellInfo) {DisposeHandle((Handle)gridCellInfo); gridCellInfo = 0;}
	
	if(err)
	{
		if(!errmsg[0])
			strcpy(errmsg,"An error occurred in NetCDFWindMoverCurv::ReorderPoints");
		printError(errmsg); 
		if(pts) {DisposeHandle((Handle)pts); pts=0;}
		if(topo) {DisposeHandle((Handle)topo); topo=0;}
		if(velH) {DisposeHandle((Handle)velH); velH=0;}
		if(tree.treeHdl) {DisposeHandle((Handle)tree.treeHdl); tree.treeHdl=0;}
		
		if(fGrid)
		{
			fGrid ->Dispose();
			delete fGrid;
			fGrid = 0;
		}
		if (verdatPtsH) {DisposeHandle((Handle)verdatPtsH); verdatPtsH = 0;}
		if (maskH2) {DisposeHandle((Handle)maskH2); maskH2 = 0;}
	}
	if (velocityH) {DisposeHandle((Handle)velocityH); velocityH = 0;}
	return err;
}
OSErr ComponentMover_c::CalculateAveragedWindsHdl(char *errmsg)
{
    OSErr err = 0;
    long i, j, numTimeSteps = (model -> GetEndTime () - model -> GetStartTime ()) / model -> GetTimeStep() + 1;
    VelocityRec value, avValue;
    TMover 		*mover;
    VelocityRec wVel = {0.,0.};
    Boolean		bFound = false;
    double pat1Theta = PI * -(0.5 + (pat1Angle / 180.0));
    double pat2Theta = PI * -(0.5 + (pat2Angle / 180.0));
    WorldPoint3D refPoint3D = {0,0,0.};
    VelocityRec pat1ValRef;
    double pat1ValRefLength;

    refPoint3D.p = refP;
    pat1ValRef = pattern1 -> GetPatValue (refPoint3D);
    pat1ValRefLength = sqrt (pat1ValRef.u * pat1ValRef.u + pat1ValRef.v * pat1ValRef.v);

    strcpy(errmsg,"");

    // calculate handle size - number of time steps, end time - start time / time step + 1
    // for each time step, start at 24 hrs (or whatever) before and average wind at each step up to current
    // if no values that far back give an error
    // put time and value in the handle
    // if error delete

    // code goes here, might want to extend handle if model run time is changed, or recreate?
    // then should delete handle in case it still exists...
    if (fAveragedWindsHdl)
    {   // should dispose at end of run??
        DisposeHandle((Handle)fAveragedWindsHdl);
        fAveragedWindsHdl = 0;
    }
    fAveragedWindsHdl = (TimeValuePairH)_NewHandleClear(sizeof(TimeValuePair)*numTimeSteps);
    if (!fAveragedWindsHdl)
    {
        TechError("TComponentMover::CalculateAveragedWindsHdl()", "_NewHandleClear()", 0);
        return -1;
    }

    // get the wind mover, if it's constant or nonexistent this is an error, should be checked in the dialog
    if (timeMoverCode == kLinkToWindMover)
    {
        long 	/*	i, j,*/ m, n;
        //	double 		length, theirLengthSq, myLengthSq, dotProduct;
        //	VelocityRec theirVelocity,myVelocity;
        //VelocityRec wVel = {0.,0.};
        TMap		*map;
        //	TMover 		*mover;
        //	Boolean		bFound = false;

        for (j = 0, m = model -> mapList -> GetItemCount() ; j < m && !bFound ; j++)
        {
            model -> mapList -> GetListItem((Ptr)&map, j);

            for (i = 0, n = map -> moverList -> GetItemCount() ; i < n ; i++)
            {
                map -> moverList -> GetListItem((Ptr)&mover, i);
                if (mover -> GetClassID() != TYPE_WINDMOVER) continue;
                if (!strcmp(mover -> className, windMoverName))
                {
                    // JLM, note: we are implicitly matching by file name above
                    //	((TWindMover*) mover) -> GetTimeValue (model -> modelTime, &wVel);
                    bFound = true;
                    break;
                }
            }

            if (!bFound)
            {
                map = model -> uMap;
                for (i = 0, n = map -> moverList -> GetItemCount() ; i < n ; i++)
                {
                    map -> moverList -> GetListItem((Ptr)&mover, i);
                    if (mover -> GetClassID() != TYPE_WINDMOVER) continue;
                    if (!strcmp(mover -> className, windMoverName))
                    {
                        // JLM, note: we are implicitly matching by file name above
                        //((TWindMover*) mover) -> GetTimeValue (model -> modelTime, &wVel);
                        bFound = true;
                        break;
                    }
                }
            }
        }

        if (!bFound)
        {
            mover =  (TMover*) (model->GetWindMover(false));	// see if there is a wind at all and use it
            if (!mover) {
                strcpy(windMoverName, "");	// clear out any value
                strcpy(errmsg,"There is no wind time file associated with the component mover");
                //printError("There is no wind time file associated with the component mover");
                return -1;
            }
            strcpy(windMoverName, mover->className);	// link the wind to the component mover
            //print error, also check if it's a constant wind or times out of range
        }
        // alert code goes here if mover is not found
    }
    else
    {
        strcpy(errmsg,"There is no wind time file associated with the component mover");
        //	printError("There is no wind time file associated with the component mover");
        return -1;
    }

    // check wind time file exists for whole length of run, including the past averaging hours
    for (i = 0 ; i < numTimeSteps ; i++)
    {
        long averageTimeSteps;
        double averageSpeed=0.,averageDir = 0;
        Seconds timeToGetAverageFor = model -> GetStartTime () + i * model -> GetTimeStep();
        Seconds startPastTime  = timeToGetAverageFor - fPastHoursToAverage * 3600;
        INDEXH(fAveragedWindsHdl, i).time = model -> GetStartTime () + i * model -> GetTimeStep();
        //averageTimeSteps = fPastHoursToAverage+1; // for now, will change to match model time steps...
        averageTimeSteps = fPastHoursToAverage; // for now, will change to match model time steps...
        // code goes here, may want to change to GetStartTime, GetEndTime, then check out of range
        if (i==0) 	err = dynamic_cast<TWindMover *>(mover)->CheckStartTime(startPastTime); //if (forTime < INDEXH(timeValues, 0).time)
        if (err==-1)
        {
            if (bExtrapolateWinds)
            {   // GetTimeValue() already extrapolates
                err = 0;
            }
            else
            {
                strcpy(errmsg,"There is not enough data in your wind file for the averaging");
                goto done;
            }
            //printError("There is not enough data in your wind file for the averaging"); goto done;
        }
        if (err==-2)
        {
            //strcpy(errmsg,"No point in averaging for constant wind."); goto done;
            //fPastHoursToAverage=0; err=0;	// allow constant wind, only need one value though
            //printError("No point in averaging for constant wind."); goto done;
            averageTimeSteps = 1;
            startPastTime = timeToGetAverageFor;	// this doesn't really matter with constant wind
            err = 0;
        }
        //if (forTime > INDEXH(timeValues, n - 1).time)

        if (fPastHoursToAverage==0) averageTimeSteps = 1;	// just use the straight wind
        for (j=0; j<averageTimeSteps; j++)
        {
            Seconds timeToAddToAverage = startPastTime + j*3600; // eventually this will be time step...
            double		windSpeedToScale, windDir,theta;
            // get the time file / wind mover value for this time
            // get the mover first then repeat using it for the times..., but make sure get time value gets a value...
            // check first value - 24, last value else will just use first/last value
            // also check if it's not a time file...
            // make sure in the GetMove to GetTimeValue from the averaged handle
            // check here that time is in the handle...
            dynamic_cast<TWindMover *>(mover)-> GetTimeValue (timeToAddToAverage, &wVel);	// minus AH 07/10/2012

            //windSpeedToScale = sqrt(wVel.u*wVel.u + wVel.v*wVel.v);
            // code goes here, take the component first, then average ?
            windSpeedToScale = wVel.u * cos (pat1Theta) + wVel.v * sin (pat1Theta);
            //averageSpeed += (windSpeedToScale) * fScaleFactorAveragedWinds / pat1ValRefLength; //windSpeedToScale; //?? need the dot product too
            //averageSpeed += (windSpeedToScale); //windSpeedToScale; //?? need the dot product too - seems this was done twice?
            //windDir = fmod(atan2(wVel.u,wVel.v)*180/PI+360,360); // floating point remainder
            windDir = atan2(wVel.u,wVel.v); //
            //windDir = fmod(-180,360); // not sure what above does...
            //theta = fmod(theta+180,360); // rotate the vector cause wind is FROM this direction
            //r=sqrt(u*u+v*v);
            //	windDir = 0;
            averageSpeed = averageSpeed + windSpeedToScale; // need to divide by averageTimeSteps
            averageDir = averageDir + windDir;
            //averageDir = averageDir + windSpeedToScale; // need to divide by averageTimeSteps
            // if add up wind dir make sure it's -180 to 180 - not necessary
        }
        averageSpeed = averageSpeed / averageTimeSteps;
        // apply power and scale - is this the right order?
        if (averageSpeed<0) averageSpeed = -1. * pow(myfabs(averageSpeed),fPowerFactorAveragedWinds);
        else
            /*if (fPowerFactorAveragedWinds!=1.)*/  averageSpeed = pow(averageSpeed,fPowerFactorAveragedWinds);
        //for now apply the scale factor in SetOptimizeVariables()
        //averageSpeed = averageSpeed*fScaleFactorAveragedWinds;
        // code goes here bUseMainDialogScaleFactor = true do this way leave out fSFAW, = false just use fSFAW
        averageDir = averageDir / averageTimeSteps;
        //avValue.u = averageSpeed*sin(averageDir/*+PI*/);	// not sure about the pi
        //avValue.v = averageSpeed*cos(averageDir/*+PI*/);
        avValue.u = averageSpeed;	// not sure about the pi
        avValue.v = 0;	// not sure about the pi
        INDEXH(fAveragedWindsHdl, i).value = avValue;// translate back to u,v

    }
done:
    if (err)
    {
        if (fAveragedWindsHdl)
        {   // should dispose at end of run??
            DisposeHandle((Handle)fAveragedWindsHdl);
            fAveragedWindsHdl = 0;
        }
    }
    return err;
}
Example #8
0
OSErr TriCurMover_c::ReadTimeData(long index,VelocityFH *velocityH, char* errmsg) 
{
	char s[256], path[256]; 
	long i,j,line = 0;
	long offset,lengthToRead;
	CHARH h = 0;
	char *sectionOfFile = 0;
	char *strToMatch = 0;
	long len,numScanned;
	VelocityFH velH = 0;
	long totalNumberOfVels = 0;
	
	LongPointHdl ptsHdl = 0;
	//TopologyHdl topoH = GetTopologyHdl();
	//TTriGridVel* triGrid = (TTriGridVel*)fGrid;
	
	OSErr err = 0;
	DateTimeRec time;
	Seconds timeSeconds;
	//long numPoints, numDepths; 
	long numTris;
	errmsg[0]=0;
	
	strcpy(path,fVar.pathName);
	if (!path || !path[0]) return -1;
	
	lengthToRead = (*fTimeDataHdl)[index].lengthOfData;
	offset = (*fTimeDataHdl)[index].fileOffsetToStartOfData;
	
	if (fDepthDataInfo)
		numTris = _GetHandleSize((Handle)fDepthDataInfo)/sizeof(**fDepthDataInfo);
	//if(topoH)
	//numTris = _GetHandleSize((Handle)topoH)/sizeof(**topoH);
	else 
	{err=-1; goto done;} // no data
	
	h = (CHARH)_NewHandle(lengthToRead+1);
	if(!h){TechError("TriCurMover::ReadTimeData()", "_NewHandle()", 0); err = memFullErr; goto done;}
	
	_HLock((Handle)h);
	sectionOfFile = *h;			
	
	err = ReadSectionOfFile(0,0,path,offset,lengthToRead,sectionOfFile,0);
	if(err || !h) 
	{
		char firstPartOfLine[128];
		sprintf(errmsg,"Unable to open data file:%s",NEWLINESTRING);
		strncpy(firstPartOfLine,path,120);
		strcpy(firstPartOfLine+120,"...");
		strcat(errmsg,firstPartOfLine);
		goto done;
	}
	sectionOfFile[lengthToRead] = 0; // make it a C string
	
	//numDepths = fVar.maxNumDepths;
	// for now we will always have a full set of velocities
	totalNumberOfVels = (*fDepthDataInfo)[numTris-1].indexToDepthData+(*fDepthDataInfo)[numTris-1].numDepths;
	//totalNumberOfVels = numTris*numDepths;
	if(totalNumberOfVels<numTris) {err=-1; goto done;} // must have at least full set of 2D velocity data
	velH = (VelocityFH)_NewHandleClear(sizeof(**velH)*totalNumberOfVels);
	if(!velH){TechError("TriCurMover::ReadTimeData()", "_NewHandle()", 0); err = memFullErr; goto done;}
	
	strToMatch = "[TIME]";
	len = strlen(strToMatch);
	NthLineInTextOptimized (sectionOfFile, line = 0, s, 256);
	if(!strncmp(s,strToMatch,len)) 
	{
		numScanned=sscanf(s+len, "%hd %hd %hd %hd %hd",
						  &time.day, &time.month, &time.year,
						  &time.hour, &time.minute) ;
		if (numScanned!= 5)
		{ err = -1; TechError("TriCurMover::ReadTimeData()", "sscanf() == 5", 0); goto done; }
		// check for constant current
		if (time.day == -1 && time.month == -1 && time.year == -1 && time.hour == -1 && time.minute == -1)
			//if (time.year == time.month == time.day == time.hour == time.minute == -1) 
		{
			timeSeconds = CONSTANTCURRENT;
		}
		else // time varying current
		{
			if (time.year < 1900)					// two digit date, so fix it
			{
				if (time.year >= 40 && time.year <= 99)	
					time.year += 1900;
				else
					time.year += 2000;					// correct for year 2000 (00 to 40)
			}
			
			time.second = 0;
			DateToSeconds (&time, &timeSeconds);
		}
		
		// check time is correct
		if (timeSeconds!=(*fTimeDataHdl)[index].time)
		{ err = -1;  strcpy(errmsg,"Can't read data - times in the file have changed."); goto done; }
		line++;
	}
	
	
	for(i=0;i<numTris;i++) // interior points
	{
		VelocityRec vel;
		char *startScan;
		long scanLength,stringIndex=0;
		long numDepths = (*fDepthDataInfo)[i].numDepths;	// allow for variable depths/velocites
		//long numDepths = fVar.maxNumDepths;
		
		char *s1 = new char[numDepths*64];
		if(!s1) {TechError("TriCurMover::ReadTimeData()", "new[]", 0); err = memFullErr; goto done;}
		
		NthLineInTextOptimized (sectionOfFile, line, s1, numDepths*64);
		//might want to check that the number of lines matches the number of triangles (ie there is data at every triangle)
		startScan = &s1[stringIndex];
		
		for(j=0;j<numDepths;j++) 
		{
			err = ScanVelocity(startScan,&vel,&scanLength); 
			// ScanVelocity is faster than scanf, but doesn't handle scientific notation. Try a scanf on error.
			if (err)
			{
				if(err!=-2 || sscanf(&s1[stringIndex],lfFix("%lf%lf"),&vel.u,&vel.v) < 2)
				{
					char firstPartOfLine[128];
					sprintf(errmsg,"Unable to read velocity data from line %ld:%s",line,NEWLINESTRING);
					strncpy(firstPartOfLine,s1,120);
					strcpy(firstPartOfLine+120,"...");
					strcat(errmsg,firstPartOfLine);
					delete[] s1; s1=0;
					goto done;
				}
				err = 0;
			}
			(*velH)[(*fDepthDataInfo)[i].indexToDepthData+j].u = vel.u; 
			(*velH)[(*fDepthDataInfo)[i].indexToDepthData+j].v = vel.v; 
			//(*velH)[i*numDepths+j].u = vel.u; 
			//(*velH)[i*numDepths+j].v = vel.v; 
			stringIndex += scanLength;
			startScan = &s1[stringIndex];
		}
		line++;
		delete[] s1; s1=0;
	}
	*velocityH = velH;
	
done:
	
	if(h) {
		_HUnlock((Handle)h); 
		DisposeHandle((Handle)h); 
		h = 0;
	}
	
	
	if(err)
	{
		if(!errmsg[0])
			strcpy(errmsg,"An error occurred in TriCurMover::ReadTimeData");
		//printError(errmsg); // This alert causes a freeze up...
		// We don't want to put up an error message here because it can lead to an infinite loop of messages.
		if(velH) {DisposeHandle((Handle)velH); velH = 0;}
	}
	return err;
	
}