void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ int i,j,k; char *filename; char *precision; DataGroup::DataType prec; const char *fieldname; const mxArray *matstruct, *matcell, *matfield; mwSize numfields; mwSize ndims; mwSize nelems; mwSize numcells; const mwSize *dims; double *dreal; double *dimag; float *sreal; float *simag; ofstream output; /* Protobuf object types */ DataStore ds; DataGroup *dg; DataValue *dv; if(nlhs != 0){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore","Mex function does not return any values."); } if(nrhs != 3 || !mxIsChar(prhs[0]) || !mxIsChar(prhs[1])){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore","Mex function takes a file name, precision string and a single structure of named literals."); } /* Check the type/precision requested */ precision = mxArrayToString(prhs[1]); if(0 == strcmp(precision, "double")){ prec = DataGroup::DOUBLE; }else if(0 == strcmp(precision, "complexdouble")){ prec = DataGroup::COMPLEXDOUBLE; }else if(0 == strcmp(precision, "float")){ prec = DataGroup::SINGLE; }else if(0 == strcmp(precision, "complexfloat")){ prec = DataGroup::COMPLEXSINGLE; }else{ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore", "Invalid precision requested '%s'.\n", precision); } mxFree(precision); matstruct = prhs[2]; ndims = mxGetNumberOfDimensions(matstruct); dims = mxGetDimensions(matstruct); /* Verify that the data input is a structure and does not have multiple dimensions */ if(!mxIsStruct(matstruct) || 2 != ndims || 1 != dims[0] || 1 != dims[1]){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore","Mex function takes file name, precision string and a single structure of named literals."); } numfields = mxGetNumberOfFields(matstruct); for(i=0;i<numfields;i++){ fieldname = mxGetFieldNameByNumber(matstruct, i); /* Check to see if struct field is a cell array */ matcell = mxGetFieldByNumber(matstruct, 0, i); if(mxIsCell(matcell)){ ndims = mxGetNumberOfDimensions(matcell); dims = mxGetDimensions(matcell); numcells = 1; for(j=0;j<ndims;j++){ numcells *= dims[j]; } matfield = mxGetCell(matcell, 0); } else{ numcells = 1; matfield = matcell; } /* Create a new DataGroup corresponding to the structure field */ dg = ds.add_group(); dg->set_name(fieldname); dg->set_type(prec); /* Add a DataValue for each cell in structure field, only one member if field is numeric */ for(j=0;j<numcells;j++){ /* Ensure data element is double precision numeric data if requested precision is double */ if(!mxIsDouble(matfield) && (DataGroup::DOUBLE == prec || DataGroup::COMPLEXDOUBLE == prec)){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore","Field '%s' does not contain a double precision numeric literal at position %d. Type is '%s'.", fieldname, j, mxGetClassName(matfield)); } /* Ensure data element is double or single precision if requested precision is single */ if(!mxIsDouble(matfield) && !mxIsSingle(matfield) && (DataGroup::SINGLE == prec || DataGroup::COMPLEXSINGLE == prec)){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore", "Field '%s' does not contain a floating point literal at position %d. Type is '%s'.", fieldname, j, mxGetClassName(matfield)); } /* Ensure data is not complex if only reals were specified */ if(mxIsComplex(matfield) && (DataGroup::DOUBLE == prec || DataGroup::SINGLE == prec)){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore", "Field '%s' contains a complex literal at position %d but only real values were requested.", fieldname, j); } /* Store the contents of the DataValue */ ndims = mxGetNumberOfDimensions(matfield); dims = mxGetDimensions(matfield); nelems = 1; /* Get pointers to the Matlab data */ if(mxIsDouble(matfield)){ dreal = mxGetPr(matfield); dimag = mxGetPi(matfield); sreal = NULL; simag = NULL; }else if(mxIsSingle(matfield)){ sreal = (float*)mxGetData(matfield); simag = (float*)mxGetImagData(matfield); dreal = NULL; dimag = NULL; } dv = dg->add_member(); for(k=0;k<ndims;k++){ nelems *= dims[k]; dv->add_dims(dims[k]); } for(k=0;k<nelems;k++){ /* Add data based on type/precision */ switch(prec){ case DataGroup::COMPLEXDOUBLE: if(dimag){ dv->add_dimag(dimag[k]); }else{ /* Value had no imaginary data, but complex type is requested */ dv->add_dimag(0.0); } /* no break, case falls through to next */ case DataGroup::DOUBLE: dv->add_dreal(dreal[k]); break; /* We allow downconversion from double to single so must check type of data */ case DataGroup::COMPLEXSINGLE: if(dimag){ dv->add_simag((float)dimag[k]); }else if(simag){ dv->add_simag(simag[k]); }else{ /* Value had no imaginary data, but complex type is requested */ dv->add_simag(0.0f); } /* no break, case falls through to next */ case DataGroup::SINGLE: if(dreal){ dv->add_sreal((float)dreal[k]); }else{ dv->add_sreal(sreal[k]); } break; } } /* If structure field is a cell array, advance to next cell */ if(numcells > 1){ matfield = mxGetCell(matcell, j+1); } } } /* Open the file */ filename = mxArrayToString(prhs[0]); output.open(filename, ios::out | ios::binary | ios::trunc); if(output.fail()){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore", "Unable to open file '%s'.", filename); } mxFree(filename); /* Write entire DataStore to file */ if(!ds.SerializeToOstream(&output)){ mexErrMsgIdAndTxt("Simatra:simEngine:mexDataStore", "Unable to serialize data to file '%s'.", filename); } output.close(); google::protobuf::ShutdownProtobufLibrary(); }