v5d.c 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153
  1. /* v5d.c */
  2. /* Vis5D version 5.0 */
  3. /*
  4. Vis5D system for visualizing five dimensional gridded data sets
  5. Copyright (C) 1990 - 1997 Bill Hibbard, Johan Kellum, Brian Paul,
  6. Dave Santek, and Andre Battaiola.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 1, or (at your option)
  10. any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. /* this should be updated when the file version changes */
  20. #define FILE_VERSION "4.3"
  21. /*
  22. * New grid file format for VIS-5D:
  23. *
  24. * The header is a list of tagged items. Each item has 3 parts:
  25. * 1. A tag which is a 4-byte integer identifying the type of item.
  26. * 2. A 4-byte integer indicating how many bytes of data follow.
  27. * 3. The binary data.
  28. *
  29. * If we need to add new information to a file header we just create a
  30. * new tag and add the code to read/write the information.
  31. *
  32. * If we're reading a header and find an unknown tag, we can use the
  33. * length field to skip ahead to the next tag. Therefore, the file
  34. * format is forward (and backward) compatible.
  35. *
  36. * Grid data is stored as either:
  37. * 1-byte unsigned integers (255=missing)
  38. * 2-byte unsigned integers (65535=missing)
  39. * 4-byte IEEE floats ( >1.0e30 = missing)
  40. *
  41. * All numeric values are stored in big endian order. All floating point
  42. * values are in IEEE format.
  43. */
  44. /*
  45. * Updates:
  46. *
  47. * April 13, 1995, brianp
  48. * finished Cray support for 2-byte and 4-byte compress modes
  49. */
  50. #include <grass/config.h>
  51. #include <assert.h>
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include <math.h>
  56. #include <grass/gis.h>
  57. #include "binio.h"
  58. #include "v5d.h"
  59. #include "vis5d.h"
  60. #ifndef SEEK_SET
  61. # define SEEK_SET 0
  62. #endif
  63. #ifndef SEEK_CUR
  64. # define SEEK_CUR 1
  65. #endif
  66. #ifndef SEEK_END
  67. # define SEEK_END 2
  68. #endif
  69. /*
  70. * Currently defined tags:
  71. * Note: the notation a[i] doesn't mean a is an array of i elements,
  72. * rather it just refers to the ith element of a[].
  73. *
  74. * Tags marked as PHASED OUT should be readable but are no longer written.
  75. * Old tag numbers can't be reused!
  76. *
  77. */
  78. /* TAG NAME VALUE DATA (comments) */
  79. /*----------------------------------------------------------------------*/
  80. #define TAG_ID 0x5635440a /* hex encoding of "V5D\n" */
  81. /* general stuff 1000+ */
  82. #define TAG_VERSION 1000 /* char*10 FileVersion */
  83. #define TAG_NUMTIMES 1001 /* int*4 NumTimes */
  84. #define TAG_NUMVARS 1002 /* int*4 NumVars */
  85. #define TAG_VARNAME 1003 /* int*4 var; char*10 VarName[var] */
  86. #define TAG_NR 1004 /* int*4 Nr */
  87. #define TAG_NC 1005 /* int*4 Nc */
  88. #define TAG_NL 1006 /* int*4 Nl (Nl for all vars) */
  89. #define TAG_NL_VAR 1007 /* int*4 var; int*4 Nl[var] */
  90. #define TAG_LOWLEV_VAR 1008 /* int*4 var; int*4 LowLev[var] */
  91. #define TAG_TIME 1010 /* int*4 t; int*4 TimeStamp[t] */
  92. #define TAG_DATE 1011 /* int*4 t; int*4 DateStamp[t] */
  93. #define TAG_MINVAL 1012 /* int*4 var; real*4 MinVal[var] */
  94. #define TAG_MAXVAL 1013 /* int*4 var; real*4 MaxVal[var] */
  95. #define TAG_COMPRESS 1014 /* int*4 CompressMode; (#bytes/grid) */
  96. #define TAG_UNITS 1015 /* int *4 var; char*20 Units[var] */
  97. /* vertical coordinate system 2000+ */
  98. #define TAG_VERTICAL_SYSTEM 2000 /* int*4 VerticalSystem */
  99. #define TAG_VERT_ARGS 2100 /* int*4 n; real*4 VertArgs[0..n-1] */
  100. #define TAG_BOTTOMBOUND 2001 /* real*4 BottomBound (PHASED OUT) */
  101. #define TAG_LEVINC 2002 /* real*4 LevInc (PHASED OUT) */
  102. #define TAG_HEIGHT 2003 /* int*4 l; real*4 Height[l] (PHASED OUT) */
  103. /* projection 3000+ */
  104. #define TAG_PROJECTION 3000 /* int*4 projection: */
  105. /* 0 = generic linear */
  106. /* 1 = cylindrical equidistant */
  107. /* 2 = Lambert conformal/Polar Stereo */
  108. /* 3 = rotated equidistant */
  109. #define TAG_PROJ_ARGS 3100 /* int *4 n; real*4 ProjArgs[0..n-1] */
  110. #define TAG_NORTHBOUND 3001 /* real*4 NorthBound (PHASED OUT) */
  111. #define TAG_WESTBOUND 3002 /* real*4 WestBound (PHASED OUT) */
  112. #define TAG_ROWINC 3003 /* real*4 RowInc (PHASED OUT) */
  113. #define TAG_COLINC 3004 /* real*4 ColInc (PHASED OUT) */
  114. #define TAG_LAT1 3005 /* real*4 Lat1 (PHASED OUT) */
  115. #define TAG_LAT2 3006 /* real*4 Lat2 (PHASED OUT) */
  116. #define TAG_POLE_ROW 3007 /* real*4 PoleRow (PHASED OUT) */
  117. #define TAG_POLE_COL 3008 /* real*4 PoleCol (PHASED OUT) */
  118. #define TAG_CENTLON 3009 /* real*4 CentralLon (PHASED OUT) */
  119. #define TAG_CENTLAT 3010 /* real*4 CentralLat (PHASED OUT) */
  120. #define TAG_CENTROW 3011 /* real*4 CentralRow (PHASED OUT) */
  121. #define TAG_CENTCOL 3012 /* real*4 CentralCol (PHASED OUT) */
  122. #define TAG_ROTATION 3013 /* real*4 Rotation (PHASED OUT) */
  123. #define TAG_END 9999
  124. /**********************************************************************/
  125. /***** Miscellaneous Functions *****/
  126. /**********************************************************************/
  127. float pressure_to_height(float pressure)
  128. {
  129. return (float)DEFAULT_LOG_EXP *log((double)pressure / DEFAULT_LOG_SCALE);
  130. }
  131. float height_to_pressure(float height)
  132. {
  133. return (float)DEFAULT_LOG_SCALE *exp((double)height / DEFAULT_LOG_EXP);
  134. }
  135. /*
  136. * Return current file position.
  137. * Input: f - file descriptor
  138. */
  139. static off_t ltell(int f)
  140. {
  141. return lseek(f, 0, SEEK_CUR);
  142. }
  143. /*
  144. * Copy up to maxlen characters from src to dst stopping upon whitespace
  145. * in src. Terminate dst with null character.
  146. * Return: length of dst.
  147. */
  148. static int copy_string2(char *dst, const char *src, int maxlen)
  149. {
  150. int i;
  151. for (i = 0; i < maxlen; i++)
  152. dst[i] = src[i];
  153. for (i = maxlen - 1; i >= 0; i--) {
  154. if (dst[i] == ' ' || i == maxlen - 1)
  155. dst[i] = 0;
  156. else
  157. break;
  158. }
  159. return strlen(dst);
  160. }
  161. /*
  162. * Copy up to maxlen characters from src to dst stopping upon whitespace
  163. * in src. Terminate dst with null character.
  164. * Return: length of dst.
  165. */
  166. static int copy_string(char *dst, const char *src, int maxlen)
  167. {
  168. int i;
  169. for (i = 0; i < maxlen; i++) {
  170. if (src[i] == ' ' || i == maxlen - 1) {
  171. dst[i] = 0;
  172. break;
  173. }
  174. else {
  175. dst[i] = src[i];
  176. }
  177. }
  178. return i;
  179. }
  180. /*
  181. * Convert a date from YYDDD format to days since Jan 1, 1900.
  182. */
  183. int v5dYYDDDtoDays(int yyddd)
  184. {
  185. int iy, id, idays;
  186. iy = yyddd / 1000;
  187. id = yyddd - 1000 * iy;
  188. if (iy < 50)
  189. iy += 100; /* WLH 31 July 96 << 31 Dec 99 */
  190. idays = 365 * iy + (iy - 1) / 4 + id;
  191. return idays;
  192. }
  193. /*
  194. * Convert a time from HHMMSS format to seconds since midnight.
  195. */
  196. int v5dHHMMSStoSeconds(int hhmmss)
  197. {
  198. int h, m, s;
  199. h = hhmmss / 10000;
  200. m = (hhmmss / 100) % 100;
  201. s = hhmmss % 100;
  202. return s + m * 60 + h * 60 * 60;
  203. }
  204. /*
  205. * Convert a day since Jan 1, 1900 to YYDDD format.
  206. */
  207. int v5dDaysToYYDDD(int days)
  208. {
  209. int iy, id, iyyddd;
  210. iy = (4 * days) / 1461;
  211. id = days - (365 * iy + (iy - 1) / 4);
  212. if (iy > 99)
  213. iy = iy - 100; /* WLH 31 July 96 << 31 Dec 99 */
  214. /* iy = iy + 1900; is the right way to fix this, but requires
  215. changing all places where dates are printed - procrastinate */
  216. iyyddd = iy * 1000 + id;
  217. return iyyddd;
  218. }
  219. /*
  220. * Convert a time in seconds since midnight to HHMMSS format.
  221. */
  222. int v5dSecondsToHHMMSS(int seconds)
  223. {
  224. int hh, mm, ss;
  225. hh = seconds / (60 * 60);
  226. mm = (seconds / 60) % 60;
  227. ss = seconds % 60;
  228. return hh * 10000 + mm * 100 + ss;
  229. }
  230. void v5dPrintStruct(const v5dstruct * v)
  231. {
  232. static char day[7][10] = { "Sunday", "Monday", "Tuesday", "Wednesday",
  233. "Thursday", "Friday", "Saturday"
  234. };
  235. int time, var, i;
  236. int maxnl;
  237. maxnl = 0;
  238. for (var = 0; var < v->NumVars; var++) {
  239. if (v->Nl[var] + v->LowLev[var] > maxnl) {
  240. maxnl = v->Nl[var] + v->LowLev[var];
  241. }
  242. }
  243. if (v->FileFormat == 0) {
  244. if (v->FileVersion[0] == 0) {
  245. printf("File format: v5d version: (4.0 or 4.1)\n");
  246. }
  247. else {
  248. printf("File format: v5d version: %s\n", v->FileVersion);
  249. }
  250. }
  251. else {
  252. printf("File format: comp5d (VIS-5D 3.3 or older)\n");
  253. }
  254. if (v->CompressMode == 1) {
  255. printf("Compression: 1 byte per gridpoint.\n");
  256. }
  257. else {
  258. printf("Compression: %d bytes per gridpoint.\n", v->CompressMode);
  259. }
  260. printf("header size=%d\n", (int)v->FirstGridPos);
  261. printf("sizeof(v5dstruct)=%d\n", (int)sizeof(v5dstruct));
  262. printf("\n");
  263. printf("NumVars = %d\n", v->NumVars);
  264. printf
  265. ("Var Name Units Rows Cols Levels LowLev MinVal MaxVal\n");
  266. for (var = 0; var < v->NumVars; var++) {
  267. printf("%3d %-10s %-10s %3d %3d %3d %3d",
  268. var + 1, v->VarName[var], v->Units[var],
  269. v->Nr, v->Nc, v->Nl[var], v->LowLev[var]);
  270. if (v->MinVal[var] > v->MaxVal[var]) {
  271. printf(" MISSING MISSING\n");
  272. }
  273. else {
  274. printf(" %-12g %-12g\n", v->MinVal[var], v->MaxVal[var]);
  275. }
  276. }
  277. printf("\n");
  278. printf("NumTimes = %d\n", v->NumTimes);
  279. printf("Step Date(YYDDD) Time(HH:MM:SS) Day\n");
  280. for (time = 0; time < v->NumTimes; time++) {
  281. int i = v->TimeStamp[time];
  282. printf("%3d %05d %5d:%02d:%02d %s\n",
  283. time + 1,
  284. v->DateStamp[time],
  285. i / 10000, (i / 100) % 100, i % 100,
  286. day[v5dYYDDDtoDays(v->DateStamp[time]) % 7]);
  287. }
  288. printf("\n");
  289. switch (v->VerticalSystem) {
  290. case 0:
  291. printf("Generic linear vertical coordinate system:\n");
  292. printf("\tBottom Bound: %f\n", v->VertArgs[0]);
  293. printf("\tIncrement between levels: %f\n", v->VertArgs[1]);
  294. break;
  295. case 1:
  296. printf("Equally spaced levels in km:\n");
  297. printf("\tBottom Bound: %f\n", v->VertArgs[0]);
  298. printf("\tIncrement: %f\n", v->VertArgs[1]);
  299. break;
  300. case 2:
  301. printf("Unequally spaced levels in km:\n");
  302. printf("Level\tHeight(km)\n");
  303. for (i = 0; i < maxnl; i++) {
  304. printf("%3d %10.3f\n", i + 1, v->VertArgs[i]);
  305. }
  306. break;
  307. case 3:
  308. printf("Unequally spaced levels in mb:\n");
  309. printf("Level\tPressure(mb)\n");
  310. for (i = 0; i < maxnl; i++) {
  311. printf("%3d %10.3f\n", i + 1,
  312. height_to_pressure(v->VertArgs[i]));
  313. }
  314. break;
  315. default:
  316. printf("Bad VerticalSystem value: %d\n", v->VerticalSystem);
  317. }
  318. printf("\n");
  319. switch (v->Projection) {
  320. case 0:
  321. printf("Generic linear projection:\n");
  322. printf("\tNorth Boundary: %f\n", v->ProjArgs[0]);
  323. printf("\tWest Boundary: %f\n", v->ProjArgs[1]);
  324. printf("\tRow Increment: %f\n", v->ProjArgs[2]);
  325. printf("\tColumn Increment: %f\n", v->ProjArgs[3]);
  326. break;
  327. case 1:
  328. printf("Cylindrical Equidistant projection:\n");
  329. printf("\tNorth Boundary: %f degrees\n", v->ProjArgs[0]);
  330. printf("\tWest Boundary: %f degrees\n", v->ProjArgs[1]);
  331. printf("\tRow Increment: %f degrees\n", v->ProjArgs[2]);
  332. printf("\tColumn Increment: %f degrees\n", v->ProjArgs[3]);
  333. /*
  334. printf("\tSouth Boundary: %f degrees\n",
  335. v->NorthBound - v->RowInc * (v->Nr-1) );
  336. printf("\tEast Boundary: %f degrees\n",
  337. v->WestBound - v->ColInc * (v->Nc-1) );
  338. */
  339. break;
  340. case 2:
  341. printf("Lambert Conformal projection:\n");
  342. printf("\tStandard Latitude 1: %f\n", v->ProjArgs[0]);
  343. printf("\tStandard Latitude 2: %f\n", v->ProjArgs[1]);
  344. printf("\tNorth/South Pole Row: %f\n", v->ProjArgs[2]);
  345. printf("\tNorth/South Pole Column: %f\n", v->ProjArgs[3]);
  346. printf("\tCentral Longitude: %f\n", v->ProjArgs[4]);
  347. printf("\tColumn Increment: %f km\n", v->ProjArgs[5]);
  348. break;
  349. case 3:
  350. printf("Stereographic:\n");
  351. printf("\tCenter Latitude: %f\n", v->ProjArgs[0]);
  352. printf("\tCenter Longitude: %f\n", v->ProjArgs[1]);
  353. printf("\tCenter Row: %f\n", v->ProjArgs[2]);
  354. printf("\tCenter Column: %f\n", v->ProjArgs[3]);
  355. printf("\tColumn Spacing: %f\n", v->ProjArgs[4]);
  356. break;
  357. case 4:
  358. /* WLH 4-21-95 */
  359. printf("Rotated equidistant projection:\n");
  360. printf("\tLatitude of grid(0,0): %f\n", v->ProjArgs[0]);
  361. printf("\tLongitude of grid(0,0): %f\n", v->ProjArgs[1]);
  362. printf("\tRow Increment: %f degress\n", v->ProjArgs[2]);
  363. printf("\tColumn Increment: %f degrees\n", v->ProjArgs[3]);
  364. printf("\tCenter Latitude: %f\n", v->ProjArgs[4]);
  365. printf("\tCenter Longitude: %f\n", v->ProjArgs[5]);
  366. printf("\tRotation: %f degrees\n", v->ProjArgs[6]);
  367. break;
  368. default:
  369. printf("Bad projection number: %d\n", v->Projection);
  370. }
  371. }
  372. /*
  373. * Compute the location of a compressed grid within a file.
  374. * Input: v - pointer to v5dstruct describing the file header.
  375. * time, var - which timestep and variable.
  376. * Return: file offset in bytes
  377. */
  378. static off_t grid_position(const v5dstruct * v, int time, int var)
  379. {
  380. int i;
  381. off_t pos;
  382. assert(time >= 0);
  383. assert(var >= 0);
  384. assert(time < v->NumTimes);
  385. assert(var < v->NumVars);
  386. pos = v->FirstGridPos + time * v->SumGridSizes;
  387. for (i = 0; i < var; i++) {
  388. pos += v->GridSize[i];
  389. }
  390. return pos;
  391. }
  392. /*
  393. * Compute the ga and gb (de)compression values for a grid.
  394. * Input: nr, nc, nl - size of grid
  395. * data - the grid data
  396. * ga, gb - arrays to store results.
  397. * minval, maxval - pointer to floats to return min, max values
  398. * compressmode - 1, 2 or 4 bytes per grid point
  399. * Output: ga, gb - the (de)compression values
  400. * minval, maxval - the min and max grid values
  401. * Side effect: the MinVal[var] and MaxVal[var] fields in g may be
  402. * updated with new values.
  403. */
  404. static void compute_ga_gb(int nr, int nc, int nl,
  405. const float data[], int compressmode,
  406. float ga[], float gb[],
  407. float *minval, float *maxval)
  408. {
  409. #ifdef SIMPLE_COMPRESSION
  410. /*
  411. * Compute ga, gb values for whole grid.
  412. */
  413. int i, lev, allmissing, num;
  414. float min, max, a, b;
  415. min = 1.0e30;
  416. max = -1.0e30;
  417. num = nr * nc * nl;
  418. allmissing = 1;
  419. for (i = 0; i < num; i++) {
  420. if (!IS_MISSING(data[i])) {
  421. if (data[i] < min)
  422. min = data[i];
  423. if (data[i] > max)
  424. max = data[i];
  425. allmissing = 0;
  426. }
  427. }
  428. if (allmissing) {
  429. a = 1.0;
  430. b = 0.0;
  431. }
  432. else {
  433. a = (max - min) / 254.0;
  434. b = min;
  435. }
  436. /* return results */
  437. for (i = 0; i < nl; i++) {
  438. ga[i] = a;
  439. gb[i] = b;
  440. }
  441. *minval = min;
  442. *maxval = max;
  443. #else
  444. /*
  445. * Compress grid on level-by-level basis.
  446. */
  447. # define SMALLVALUE -1.0e30
  448. # define BIGVALUE 1.0e30
  449. # define ABS(x) ( ((x) < 0.0) ? -(x) : (x) )
  450. float gridmin, gridmax;
  451. float levmin[MAXLEVELS], levmax[MAXLEVELS];
  452. float d[MAXLEVELS], dmax;
  453. float ival, mval;
  454. int j, k, lev, nrnc;
  455. nrnc = nr * nc;
  456. /* find min and max for each layer and the whole grid */
  457. gridmin = BIGVALUE;
  458. gridmax = SMALLVALUE;
  459. j = 0;
  460. for (lev = 0; lev < nl; lev++) {
  461. float min, max;
  462. min = BIGVALUE;
  463. max = SMALLVALUE;
  464. for (k = 0; k < nrnc; k++) {
  465. if (!IS_MISSING(data[j]) && data[j] < min)
  466. min = data[j];
  467. if (!IS_MISSING(data[j]) && data[j] > max)
  468. max = data[j];
  469. j++;
  470. }
  471. if (min < gridmin)
  472. gridmin = min;
  473. if (max > gridmax)
  474. gridmax = max;
  475. levmin[lev] = min;
  476. levmax[lev] = max;
  477. }
  478. /* WLH 2-2-95 */
  479. #ifdef KLUDGE
  480. /* if the grid minimum is within delt of 0.0, fudge all values */
  481. /* within delt of 0.0 to delt, and recalculate mins and maxes */
  482. {
  483. float delt;
  484. int nrncnl = nrnc * nl;
  485. delt = (gridmax - gridmin) / 100000.0;
  486. if (ABS(gridmin) < delt && gridmin != 0.0 && compressmode != 4) {
  487. float min, max;
  488. for (j = 0; j < nrncnl; j++) {
  489. if (!IS_MISSING(data[j]) && data[j] < delt)
  490. data[j] = delt;
  491. }
  492. /* re-calculate min and max for each layer and the whole grid */
  493. gridmin = delt;
  494. for (lev = 0; lev < nl; lev++) {
  495. if (ABS(levmin[lev]) < delt)
  496. levmin[lev] = delt;
  497. if (ABS(levmax[lev]) < delt)
  498. levmax[lev] = delt;
  499. }
  500. }
  501. }
  502. #endif
  503. /* find d[lev] and dmax = MAX( d[0], d[1], ... d[nl-1] ) */
  504. dmax = 0.0;
  505. for (lev = 0; lev < nl; lev++) {
  506. if (levmin[lev] >= BIGVALUE && levmax[lev] <= SMALLVALUE) {
  507. /* all values in the layer are MISSING */
  508. d[lev] = 0.0;
  509. }
  510. else {
  511. d[lev] = levmax[lev] - levmin[lev];
  512. }
  513. if (d[lev] > dmax)
  514. dmax = d[lev];
  515. }
  516. /*** Compute ga (scale) and gb (bias) for each grid level */
  517. if (dmax == 0.0) {
  518. /*** Special cases ***/
  519. if (gridmin == gridmax) {
  520. /*** whole grid is of same value ***/
  521. for (lev = 0; lev < nl; lev++) {
  522. ga[lev] = gridmin;
  523. gb[lev] = 0.0;
  524. }
  525. }
  526. else {
  527. /*** every layer is of a single value ***/
  528. for (lev = 0; lev < nl; lev++) {
  529. ga[lev] = levmin[lev];
  530. gb[lev] = 0.0;
  531. }
  532. }
  533. }
  534. else {
  535. /*** Normal cases ***/
  536. if (compressmode == 1) {
  537. #define ORIGINAL
  538. #ifdef ORIGINAL
  539. ival = dmax / 254.0;
  540. mval = gridmin;
  541. for (lev = 0; lev < nl; lev++) {
  542. ga[lev] = ival;
  543. gb[lev] = mval + ival * (int)((levmin[lev] - mval) / ival);
  544. }
  545. #else
  546. for (lev = 0; lev < nl; lev++) {
  547. if (d[lev] == 0.0) {
  548. ival = 1.0;
  549. }
  550. else {
  551. ival = d[lev] / 254.0;
  552. }
  553. ga[lev] = ival;
  554. gb[lev] = levmin[lev];
  555. }
  556. #endif
  557. }
  558. else if (compressmode == 2) {
  559. ival = dmax / 65534.0;
  560. mval = gridmin;
  561. for (lev = 0; lev < nl; lev++) {
  562. ga[lev] = ival;
  563. gb[lev] = mval + ival * (int)((levmin[lev] - mval) / ival);
  564. }
  565. }
  566. else {
  567. assert(compressmode == 4);
  568. for (lev = 0; lev < nl; lev++) {
  569. ga[lev] = 1.0;
  570. gb[lev] = 0.0;
  571. }
  572. }
  573. }
  574. /* update min, max values */
  575. *minval = gridmin;
  576. *maxval = gridmax;
  577. #endif
  578. }
  579. /*
  580. * Compress a 3-D grid from floats to 1-byte unsigned integers.
  581. * Input: nr, nc, nl - size of grid
  582. * compressmode - 1, 2 or 4 bytes per grid point
  583. * data - array of [nr*nc*nl] floats
  584. * compdata - pointer to array of [nr*nc*nl*compressmode] bytes
  585. * to put results into.
  586. * ga, gb - pointer to arrays to put ga and gb decompression values
  587. * minval, maxval - pointers to float to return min & max values
  588. * Output: compdata - the compressed grid data
  589. * ga, gb - the decompression values
  590. * minval, maxval - the min and max grid values
  591. */
  592. void v5dCompressGrid(int nr, int nc, int nl, int compressmode,
  593. const float data[],
  594. void *compdata, float ga[], float gb[],
  595. float *minval, float *maxval)
  596. {
  597. int nrnc = nr * nc;
  598. int nrncnl = nr * nc * nl;
  599. V5Dubyte *compdata1 = (V5Dubyte *) compdata;
  600. V5Dushort *compdata2 = (V5Dushort *) compdata;
  601. /* compute ga, gb values */
  602. compute_ga_gb(nr, nc, nl, data, compressmode, ga, gb, minval, maxval);
  603. /* compress the data */
  604. if (compressmode == 1) {
  605. int i, lev, p;
  606. p = 0;
  607. for (lev = 0; lev < nl; lev++) {
  608. float one_over_a, b;
  609. b = gb[lev] - 0.0001; /* subtract an epsilon so the int((d-b)/a) */
  610. /* expr below doesn't get mis-truncated. */
  611. if (ga[lev] == 0.0) {
  612. one_over_a = 1.0;
  613. }
  614. else {
  615. one_over_a = 1.0 / ga[lev];
  616. }
  617. for (i = 0; i < nrnc; i++, p++) {
  618. if (IS_MISSING(data[p])) {
  619. compdata1[p] = 255;
  620. }
  621. else {
  622. compdata1[p] =
  623. (V5Dubyte) (int)((data[p] - b) * one_over_a);
  624. if (compdata1[p] >= 255) {
  625. compdata1[p] = (V5Dubyte) (int)(255.0 - .0001);
  626. }
  627. }
  628. }
  629. }
  630. }
  631. else if (compressmode == 2) {
  632. int i, lev, p;
  633. p = 0;
  634. for (lev = 0; lev < nl; lev++) {
  635. float one_over_a, b;
  636. b = gb[lev] - 0.0001;
  637. if (ga[lev] == 0.0) {
  638. one_over_a = 1.0;
  639. }
  640. else {
  641. one_over_a = 1.0 / ga[lev];
  642. }
  643. #ifdef _CRAY
  644. /* this is tricky because sizeof(V5Dushort)==8, not 2 */
  645. for (i = 0; i < nrnc; i++, p++) {
  646. V5Dushort compvalue;
  647. if (IS_MISSING(data[p])) {
  648. compvalue = 65535;
  649. }
  650. else {
  651. compvalue = (V5Dushort) (int)((data[p] - b) * one_over_a);
  652. }
  653. compdata1[p * 2 + 0] = compvalue >> 8; /* upper byte */
  654. compdata1[p * 2 + 1] = compvalue & 0xffu; /* lower byte */
  655. }
  656. #else
  657. for (i = 0; i < nrnc; i++, p++) {
  658. if (IS_MISSING(data[p])) {
  659. compdata2[p] = 65535;
  660. }
  661. else {
  662. compdata2[p] =
  663. (V5Dushort) (int)((data[p] - b) * one_over_a);
  664. }
  665. }
  666. /* TODO: byte-swapping on little endian??? */
  667. #endif
  668. }
  669. }
  670. else {
  671. /* compressmode==4 */
  672. #ifdef _CRAY
  673. cray_to_ieee_array(compdata, data, nrncnl);
  674. #else
  675. /* other machines: just copy 4-byte IEEE floats */
  676. assert(sizeof(float) == 4);
  677. memcpy(compdata, data, nrncnl * 4);
  678. /* TODO: byte-swapping on little endian??? */
  679. #endif
  680. }
  681. }
  682. /*
  683. * Decompress a 3-D grid from 1-byte integers to 4-byte floats.
  684. * Input: nr, nc, nl - size of grid
  685. * compdata - array of [nr*nr*nl*compressmode] bytes
  686. * ga, gb - arrays of decompression factors
  687. * compressmode - 1, 2 or 4 bytes per grid point
  688. * data - address to put decompressed values
  689. * Output: data - uncompressed floating point data values
  690. */
  691. void v5dDecompressGrid(int nr, int nc, int nl, int compressmode,
  692. void *compdata, float ga[], float gb[], float data[])
  693. {
  694. int nrnc = nr * nc;
  695. int nrncnl = nr * nc * nl;
  696. V5Dubyte *compdata1 = (V5Dubyte *) compdata;
  697. V5Dushort *compdata2 = (V5Dushort *) compdata;
  698. if (compressmode == 1) {
  699. int p, i, lev;
  700. p = 0;
  701. for (lev = 0; lev < nl; lev++) {
  702. float a = ga[lev];
  703. float b = gb[lev];
  704. /* WLH 2-2-95 */
  705. float d, aa;
  706. int id;
  707. if (a > 0.0000000001) {
  708. d = b / a;
  709. id = floor(d);
  710. d = d - id;
  711. aa = a * 0.000001;
  712. }
  713. else {
  714. id = 1;
  715. }
  716. if (-254 <= id && id <= 0 && d < aa) {
  717. for (i = 0; i < nrnc; i++, p++) {
  718. if (compdata1[p] == 255) {
  719. data[p] = MISSING;
  720. }
  721. else {
  722. data[p] = (float)(int)compdata1[p] * a + b;
  723. if (fabs(data[p]) < aa)
  724. data[p] = aa;
  725. }
  726. }
  727. }
  728. else {
  729. for (i = 0; i < nrnc; i++, p++) {
  730. if (compdata1[p] == 255) {
  731. data[p] = MISSING;
  732. }
  733. else {
  734. data[p] = (float)(int)compdata1[p] * a + b;
  735. }
  736. }
  737. }
  738. /* end of WLH 2-2-95 */
  739. }
  740. }
  741. else if (compressmode == 2) {
  742. int p, i, lev;
  743. p = 0;
  744. for (lev = 0; lev < nl; lev++) {
  745. float a = ga[lev];
  746. float b = gb[lev];
  747. #ifdef _CRAY
  748. /* this is tricky because sizeof(V5Dushort)==8, not 2 */
  749. for (i = 0; i < nrnc; i++, p++) {
  750. int compvalue;
  751. compvalue = (compdata1[p * 2] << 8) | compdata1[p * 2 + 1];
  752. if (compvalue == 65535) {
  753. data[p] = MISSING;
  754. }
  755. else {
  756. data[p] = (float)compvalue *a + b;
  757. }
  758. }
  759. #else
  760. /* sizeof(V5Dushort)==2! */
  761. for (i = 0; i < nrnc; i++, p++) {
  762. if (compdata2[p] == 65535) {
  763. data[p] = MISSING;
  764. }
  765. else {
  766. data[p] = (float)(int)compdata2[p] * a + b;
  767. }
  768. }
  769. #endif
  770. }
  771. }
  772. else {
  773. /* compressmode==4 */
  774. #ifdef _CRAY
  775. ieee_to_cray_array(data, compdata, nrncnl);
  776. #else
  777. /* other machines: just copy 4-byte IEEE floats */
  778. assert(sizeof(float) == 4);
  779. memcpy(data, compdata, nrncnl * 4);
  780. #endif
  781. }
  782. }
  783. /*
  784. * Return the size (in bytes) of the 3-D grid specified by time and var.
  785. * Input: v - pointer to v5dstruct describing the file
  786. * time, var - which timestep and variable
  787. * Return: number of data points.
  788. */
  789. int v5dSizeofGrid(const v5dstruct * v, int time, int var)
  790. {
  791. return v->Nr * v->Nc * v->Nl[var] * v->CompressMode;
  792. }
  793. /*
  794. * Initialize a v5dstructure to reasonable initial values.
  795. * Input: v - pointer to v5dstruct.
  796. */
  797. void v5dInitStruct(v5dstruct * v)
  798. {
  799. int i;
  800. /* set everything to zero */
  801. memset(v, 0, sizeof(v5dstruct));
  802. /* special cases */
  803. v->Projection = -1;
  804. v->VerticalSystem = -1;
  805. for (i = 0; i < MAXVARS; i++) {
  806. v->MinVal[i] = MISSING;
  807. v->MaxVal[i] = -MISSING;
  808. v->LowLev[i] = 0;
  809. }
  810. /* set file version */
  811. strcpy(v->FileVersion, FILE_VERSION);
  812. v->CompressMode = 1;
  813. v->FileDesc = -1;
  814. }
  815. /*
  816. * Return a pointer to a new, initialized v5dstruct.
  817. */
  818. v5dstruct *v5dNewStruct(void)
  819. {
  820. v5dstruct *v;
  821. v = (v5dstruct *) G_malloc(sizeof(v5dstruct));
  822. if (v) {
  823. v5dInitStruct(v);
  824. }
  825. return v;
  826. }
  827. /*
  828. * Free an initialized v5dstruct. (Todd Plessel)
  829. */
  830. void v5dFreeStruct(v5dstruct * v)
  831. {
  832. /*assert( v5dVerifyStruct( v ) ); */
  833. G_free(v);
  834. v = 0;
  835. }
  836. /*
  837. * Do some checking that the information in a v5dstruct is valid.
  838. * Input: v - pointer to v5dstruct
  839. * Return: 1 = g is ok, 0 = g is invalid
  840. */
  841. int v5dVerifyStruct(const v5dstruct * v)
  842. {
  843. int var, i, invalid, maxnl;
  844. invalid = 0;
  845. if (!v)
  846. return 0;
  847. /* Number of variables */
  848. if (v->NumVars < 0) {
  849. printf("Invalid number of variables: %d\n", v->NumVars);
  850. invalid = 1;
  851. }
  852. else if (v->NumVars > MAXVARS) {
  853. printf("Too many variables: %d (Maximum is %d)\n",
  854. v->NumVars, MAXVARS);
  855. invalid = 1;
  856. }
  857. /* Variable Names */
  858. for (i = 0; i < v->NumVars; i++) {
  859. if (v->VarName[i][0] == 0) {
  860. printf("Missing variable name: VarName[%d]=\"\"\n", i);
  861. invalid = 1;
  862. }
  863. }
  864. /* Number of timesteps */
  865. if (v->NumTimes < 0) {
  866. printf("Invalid number of timesteps: %d\n", v->NumTimes);
  867. invalid = 1;
  868. }
  869. else if (v->NumTimes > MAXTIMES) {
  870. printf("Too many timesteps: %d (Maximum is %d)\n",
  871. v->NumTimes, MAXTIMES);
  872. invalid = 1;
  873. }
  874. /* Make sure timestamps are increasing */
  875. for (i = 1; i < v->NumTimes; i++) {
  876. int date0 = v5dYYDDDtoDays(v->DateStamp[i - 1]);
  877. int date1 = v5dYYDDDtoDays(v->DateStamp[i]);
  878. int time0 = v5dHHMMSStoSeconds(v->TimeStamp[i - 1]);
  879. int time1 = v5dHHMMSStoSeconds(v->TimeStamp[i]);
  880. if (time1 <= time0 && date1 <= date0) {
  881. printf("Timestamp for step %d must be later than step %d\n", i,
  882. i - 1);
  883. invalid = 1;
  884. }
  885. }
  886. /* Rows */
  887. if (v->Nr < 2) {
  888. printf("Too few rows: %d (2 is minimum)\n", v->Nr);
  889. invalid = 1;
  890. }
  891. else if (v->Nr > MAXROWS) {
  892. printf("Too many rows: %d (%d is maximum)\n", v->Nr, MAXROWS);
  893. invalid = 1;
  894. }
  895. /* Columns */
  896. if (v->Nc < 2) {
  897. printf("Too few columns: %d (2 is minimum)\n", v->Nc);
  898. invalid = 1;
  899. }
  900. else if (v->Nc > MAXCOLUMNS) {
  901. printf("Too many columns: %d (%d is maximum)\n", v->Nc, MAXCOLUMNS);
  902. invalid = 1;
  903. }
  904. /* Levels */
  905. maxnl = 0;
  906. for (var = 0; var < v->NumVars; var++) {
  907. if (v->LowLev[var] < 0) {
  908. printf("Low level cannot be negative for var %s: %d\n",
  909. v->VarName[var], v->LowLev[var]);
  910. invalid = 1;
  911. }
  912. if (v->Nl[var] < 1) {
  913. printf("Too few levels for var %s: %d (1 is minimum)\n",
  914. v->VarName[var], v->Nl[var]);
  915. invalid = 1;
  916. }
  917. if (v->Nl[var] + v->LowLev[var] > MAXLEVELS) {
  918. printf("Too many levels for var %s: %d (%d is maximum)\n",
  919. v->VarName[var], v->Nl[var] + v->LowLev[var], MAXLEVELS);
  920. invalid = 1;
  921. }
  922. if (v->Nl[var] + v->LowLev[var] > maxnl) {
  923. maxnl = v->Nl[var] + v->LowLev[var];
  924. }
  925. }
  926. if (v->CompressMode != 1 && v->CompressMode != 2 && v->CompressMode != 4) {
  927. printf("Bad CompressMode: %d (must be 1, 2 or 4)\n", v->CompressMode);
  928. invalid = 1;
  929. }
  930. switch (v->VerticalSystem) {
  931. case 0:
  932. case 1:
  933. if (v->VertArgs[1] == 0.0) {
  934. printf("Vertical level increment is zero, must be non-zero\n");
  935. invalid = 1;
  936. }
  937. break;
  938. case 2:
  939. /* Check that Height values increase upward */
  940. for (i = 1; i < maxnl; i++) {
  941. if (v->VertArgs[i] <= v->VertArgs[i - 1]) {
  942. printf
  943. ("Height[%d]=%f <= Height[%d]=%f, level heights must increase\n",
  944. i, v->VertArgs[i], i - 1, v->VertArgs[i - 1]);
  945. invalid = 1;
  946. break;
  947. }
  948. }
  949. break;
  950. case 3:
  951. /* Check that Pressure values decrease upward */
  952. for (i = 1; i < maxnl; i++) {
  953. if (v->VertArgs[i] <= v->VertArgs[i - 1]) {
  954. printf
  955. ("Pressure[%d]=%f >= Pressure[%d]=%f, level pressures must decrease\n",
  956. i, height_to_pressure(v->VertArgs[i]), i - 1,
  957. height_to_pressure(v->VertArgs[i - 1]));
  958. invalid = 1;
  959. break;
  960. }
  961. }
  962. break;
  963. default:
  964. printf("VerticalSystem = %d, must be in 0..3\n", v->VerticalSystem);
  965. invalid = 1;
  966. }
  967. switch (v->Projection) {
  968. case 0: /* Generic */
  969. if (v->ProjArgs[2] == 0.0) {
  970. printf("Row Increment (ProjArgs[2]) can't be zero\n");
  971. invalid = 1;
  972. }
  973. if (v->ProjArgs[3] == 0.0) {
  974. printf("Column increment (ProjArgs[3]) can't be zero\n");
  975. invalid = 1;
  976. }
  977. break;
  978. case 1: /* Cylindrical equidistant */
  979. if (v->ProjArgs[2] < 0.0) {
  980. printf("Row Increment (ProjArgs[2]) = %g (must be >=0.0)\n",
  981. v->ProjArgs[2]);
  982. invalid = 1;
  983. }
  984. if (v->ProjArgs[3] <= 0.0) {
  985. printf("Column Increment (ProjArgs[3]) = %g (must be >=0.0)\n",
  986. v->ProjArgs[3]);
  987. invalid = 1;
  988. }
  989. break;
  990. case 2: /* Lambert Conformal */
  991. if (v->ProjArgs[0] < -90.0 || v->ProjArgs[0] > 90.0) {
  992. printf("Lat1 (ProjArgs[0]) out of range: %g\n", v->ProjArgs[0]);
  993. invalid = 1;
  994. }
  995. if (v->ProjArgs[1] < -90.0 || v->ProjArgs[1] > 90.0) {
  996. printf("Lat2 (ProjArgs[1] out of range: %g\n", v->ProjArgs[1]);
  997. invalid = 1;
  998. }
  999. if (v->ProjArgs[5] <= 0.0) {
  1000. printf("ColInc (ProjArgs[5]) = %g (must be >=0.0)\n",
  1001. v->ProjArgs[5]);
  1002. invalid = 1;
  1003. }
  1004. break;
  1005. case 3: /* Stereographic */
  1006. if (v->ProjArgs[0] < -90.0 || v->ProjArgs[0] > 90.0) {
  1007. printf("Central Latitude (ProjArgs[0]) out of range: ");
  1008. printf("%g (must be in +/-90)\n", v->ProjArgs[0]);
  1009. invalid = 1;
  1010. }
  1011. if (v->ProjArgs[1] < -180.0 || v->ProjArgs[1] > 180.0) {
  1012. printf("Central Longitude (ProjArgs[1]) out of range: ");
  1013. printf("%g (must be in +/-180)\n", v->ProjArgs[1]);
  1014. invalid = 1;
  1015. }
  1016. if (v->ProjArgs[4] < 0) {
  1017. printf("Column spacing (ProjArgs[4]) = %g (must be positive)\n",
  1018. v->ProjArgs[4]);
  1019. invalid = 1;
  1020. }
  1021. break;
  1022. case 4: /* Rotated */
  1023. /* WLH 4-21-95 */
  1024. if (v->ProjArgs[2] <= 0.0) {
  1025. printf("Row Increment (ProjArgs[2]) = %g (must be >=0.0)\n",
  1026. v->ProjArgs[2]);
  1027. invalid = 1;
  1028. }
  1029. if (v->ProjArgs[3] <= 0.0) {
  1030. printf("Column Increment = (ProjArgs[3]) %g (must be >=0.0)\n",
  1031. v->ProjArgs[3]);
  1032. invalid = 1;
  1033. }
  1034. if (v->ProjArgs[4] < -90.0 || v->ProjArgs[4] > 90.0) {
  1035. printf("Central Latitude (ProjArgs[4]) out of range: ");
  1036. printf("%g (must be in +/-90)\n", v->ProjArgs[4]);
  1037. invalid = 1;
  1038. }
  1039. if (v->ProjArgs[5] < -180.0 || v->ProjArgs[5] > 180.0) {
  1040. printf("Central Longitude (ProjArgs[5]) out of range: ");
  1041. printf("%g (must be in +/-180)\n", v->ProjArgs[5]);
  1042. invalid = 1;
  1043. }
  1044. if (v->ProjArgs[6] < -180.0 || v->ProjArgs[6] > 180.0) {
  1045. printf("Central Longitude (ProjArgs[6]) out of range: ");
  1046. printf("%g (must be in +/-180)\n", v->ProjArgs[6]);
  1047. invalid = 1;
  1048. }
  1049. break;
  1050. default:
  1051. printf("Projection = %d, must be in 0..4\n", v->Projection);
  1052. invalid = 1;
  1053. }
  1054. return !invalid;
  1055. }
  1056. /*
  1057. * Get the McIDAS file number and grid number associated with the grid
  1058. * identified by time and var.
  1059. * Input: v - v5d grid struct
  1060. * time, var - timestep and variable of grid
  1061. * Output: mcfile, mcgrid - McIDAS grid file number and grid number
  1062. */
  1063. int v5dGetMcIDASgrid(v5dstruct * v, int time, int var,
  1064. int *mcfile, int *mcgrid)
  1065. {
  1066. if (time < 0 || time >= v->NumTimes) {
  1067. printf("Bad time argument to v5dGetMcIDASgrid: %d\n", time);
  1068. return 0;
  1069. }
  1070. if (var < 0 || var >= v->NumVars) {
  1071. printf("Bad var argument to v5dGetMcIDASgrid: %d\n", var);
  1072. return 0;
  1073. }
  1074. *mcfile = (int)v->McFile[time][var];
  1075. *mcgrid = (int)v->McGrid[time][var];
  1076. return 1;
  1077. }
  1078. /*
  1079. * Set the McIDAS file number and grid number associated with the grid
  1080. * identified by time and var.
  1081. * Input: v - v5d grid struct
  1082. * time, var - timestep and variable of grid
  1083. * mcfile, mcgrid - McIDAS grid file number and grid number
  1084. * Return: 1 = ok, 0 = error (bad time or var)
  1085. */
  1086. int v5dSetMcIDASgrid(v5dstruct * v, int time, int var, int mcfile, int mcgrid)
  1087. {
  1088. if (time < 0 || time >= v->NumTimes) {
  1089. printf("Bad time argument to v5dSetMcIDASgrid: %d\n", time);
  1090. return 0;
  1091. }
  1092. if (var < 0 || var >= v->NumVars) {
  1093. printf("Bad var argument to v5dSetMcIDASgrid: %d\n", var);
  1094. return 0;
  1095. }
  1096. v->McFile[time][var] = (short)mcfile;
  1097. v->McGrid[time][var] = (short)mcgrid;
  1098. return 1;
  1099. }
  1100. /**********************************************************************/
  1101. /***** Input Functions *****/
  1102. /**********************************************************************/
  1103. /*
  1104. * Read the header from a COMP* file and return results in the v5dstruct.
  1105. * Input: f - the file descriptor
  1106. * v - pointer to a v5dstruct.
  1107. * Return: 1 = ok, 0 = error.
  1108. */
  1109. static int read_comp_header(int f, v5dstruct * v)
  1110. {
  1111. unsigned int id;
  1112. /* reset file position to start of file */
  1113. lseek(f, 0, SEEK_SET);
  1114. /* read file ID */
  1115. read_int4(f, (int *)&id);
  1116. if (id == 0x80808080 || id == 0x80808081) {
  1117. /* Older COMP5D format */
  1118. int gridtimes, gridparms;
  1119. int i, j, it, iv, nl;
  1120. off_t gridsize;
  1121. float hgttop, hgtinc;
  1122. /*char *compgrid; */
  1123. if (id == 0x80808080) {
  1124. /* 20 vars, 300 times */
  1125. gridtimes = 300;
  1126. gridparms = 20;
  1127. }
  1128. else {
  1129. /* 30 vars, 400 times */
  1130. gridtimes = 400;
  1131. gridparms = 30;
  1132. }
  1133. v->FirstGridPos = 12 * 4 + 8 * gridtimes + 4 * gridparms;
  1134. read_int4(f, &v->NumTimes);
  1135. read_int4(f, &v->NumVars);
  1136. read_int4(f, &v->Nr);
  1137. read_int4(f, &v->Nc);
  1138. read_int4(f, &nl);
  1139. for (i = 0; i < v->NumVars; i++) {
  1140. v->Nl[i] = nl;
  1141. v->LowLev[i] = 0;
  1142. }
  1143. read_float4(f, &v->ProjArgs[0]);
  1144. read_float4(f, &v->ProjArgs[1]);
  1145. read_float4(f, &hgttop);
  1146. read_float4(f, &v->ProjArgs[2]);
  1147. read_float4(f, &v->ProjArgs[3]);
  1148. read_float4(f, &hgtinc);
  1149. /*
  1150. for (i=0;i<nl;i++) {
  1151. v->Height[nl-i-1] = hgttop - i * hgtinc;
  1152. }
  1153. */
  1154. v->VerticalSystem = 1;
  1155. v->VertArgs[0] = hgttop - hgtinc * (nl - 1);
  1156. v->VertArgs[1] = hgtinc;
  1157. /* read dates and times */
  1158. for (i = 0; i < gridtimes; i++) {
  1159. read_int4(f, &j);
  1160. v->DateStamp[i] = v5dDaysToYYDDD(j);
  1161. }
  1162. for (i = 0; i < gridtimes; i++) {
  1163. read_int4(f, &j);
  1164. v->TimeStamp[i] = v5dSecondsToHHMMSS(j);
  1165. }
  1166. /* read variable names */
  1167. for (i = 0; i < gridparms; i++) {
  1168. char name[4];
  1169. read_bytes(f, name, 4);
  1170. /* remove trailing spaces, if any */
  1171. for (j = 3; j > 0; j--) {
  1172. if (name[j] == ' ' || name[j] == 0)
  1173. name[j] = 0;
  1174. else
  1175. break;
  1176. }
  1177. strncpy(v->VarName[i], name, 4);
  1178. v->VarName[i][4] = 0;
  1179. }
  1180. gridsize = ((v->Nr * v->Nc * nl + 3) / 4) * 4;
  1181. for (i = 0; i < v->NumVars; i++) {
  1182. v->GridSize[i] = 8 + gridsize;
  1183. }
  1184. v->SumGridSizes = (8 + gridsize) * v->NumVars;
  1185. /* read the grids and their ga,gb values to find min and max values */
  1186. for (i = 0; i < v->NumVars; i++) {
  1187. v->MinVal[i] = 999999.9;
  1188. v->MaxVal[i] = -999999.9;
  1189. }
  1190. /*compgrid = (char *) G_malloc ( gridsize ); */
  1191. for (it = 0; it < v->NumTimes; it++) {
  1192. for (iv = 0; iv < v->NumVars; iv++) {
  1193. float ga, gb;
  1194. float min, max;
  1195. read_float4(f, &ga);
  1196. read_float4(f, &gb);
  1197. /* skip ahead by 'gridsize' bytes */
  1198. if (lseek(f, gridsize, SEEK_CUR) == -1) {
  1199. printf("Error: Unexpected end of file, ");
  1200. printf("file may be corrupted.\n");
  1201. return 0;
  1202. }
  1203. min = -(125.0 + gb) / ga;
  1204. max = (125.0 - gb) / ga;
  1205. if (min < v->MinVal[iv])
  1206. v->MinVal[iv] = min;
  1207. if (max > v->MaxVal[iv])
  1208. v->MaxVal[iv] = max;
  1209. }
  1210. }
  1211. /*G_free ( compgrid ); */
  1212. /* done */
  1213. }
  1214. else if (id == 0x80808082 || id == 0x80808083) {
  1215. /* Newer COMP5D format */
  1216. int gridtimes, gridsize;
  1217. int it, iv, nl, i, j;
  1218. float delta;
  1219. read_int4(f, &gridtimes);
  1220. read_int4(f, &v->NumVars);
  1221. read_int4(f, &v->NumTimes);
  1222. read_int4(f, &v->Nr);
  1223. read_int4(f, &v->Nc);
  1224. read_int4(f, &nl);
  1225. for (i = 0; i < v->NumVars; i++) {
  1226. v->Nl[i] = nl;
  1227. }
  1228. read_float4(f, &v->ProjArgs[2]);
  1229. read_float4(f, &v->ProjArgs[3]);
  1230. /* Read height and determine if equal spacing */
  1231. v->VerticalSystem = 1;
  1232. for (i = 0; i < nl; i++) {
  1233. read_float4(f, &v->VertArgs[i]);
  1234. if (i == 1) {
  1235. delta = v->VertArgs[1] - v->VertArgs[0];
  1236. }
  1237. else if (i > 1) {
  1238. if (delta != (v->VertArgs[i] - v->VertArgs[i - 1])) {
  1239. v->VerticalSystem = 2;
  1240. }
  1241. }
  1242. }
  1243. if (v->VerticalSystem == 1) {
  1244. v->VertArgs[1] = delta;
  1245. }
  1246. /* read variable names */
  1247. for (iv = 0; iv < v->NumVars; iv++) {
  1248. char name[8];
  1249. read_bytes(f, name, 8);
  1250. /* remove trailing spaces, if any */
  1251. for (j = 7; j > 0; j--) {
  1252. if (name[j] == ' ' || name[j] == 0)
  1253. name[j] = 0;
  1254. else
  1255. break;
  1256. }
  1257. strncpy(v->VarName[iv], name, 8);
  1258. v->VarName[iv][8] = 0;
  1259. }
  1260. for (iv = 0; iv < v->NumVars; iv++) {
  1261. read_float4(f, &v->MinVal[iv]);
  1262. }
  1263. for (iv = 0; iv < v->NumVars; iv++) {
  1264. read_float4(f, &v->MaxVal[iv]);
  1265. }
  1266. for (it = 0; it < gridtimes; it++) {
  1267. read_int4(f, &j);
  1268. v->TimeStamp[it] = v5dSecondsToHHMMSS(j);
  1269. }
  1270. for (it = 0; it < gridtimes; it++) {
  1271. read_int4(f, &j);
  1272. v->DateStamp[it] = v5dDaysToYYDDD(j);
  1273. }
  1274. for (it = 0; it < gridtimes; it++) {
  1275. float nlat;
  1276. read_float4(f, &nlat);
  1277. if (it == 0)
  1278. v->ProjArgs[0] = nlat;
  1279. }
  1280. for (it = 0; it < gridtimes; it++) {
  1281. float wlon;
  1282. read_float4(f, &wlon);
  1283. if (it == 0)
  1284. v->ProjArgs[1] = wlon;
  1285. }
  1286. /* calculate grid storage sizes */
  1287. if (id == 0x80808082) {
  1288. gridsize = nl * 2 * 4 + ((v->Nr * v->Nc * nl + 3) / 4) * 4;
  1289. }
  1290. else {
  1291. /* McIDAS grid and file numbers present */
  1292. gridsize = 8 + nl * 2 * 4 + ((v->Nr * v->Nc * nl + 3) / 4) * 4;
  1293. }
  1294. for (i = 0; i < v->NumVars; i++) {
  1295. v->GridSize[i] = gridsize;
  1296. }
  1297. v->SumGridSizes = (off_t)gridsize * v->NumVars;
  1298. /* read McIDAS numbers??? */
  1299. /* size (in bytes) of all header info */
  1300. v->FirstGridPos =
  1301. 9 * 4 + v->Nl[0] * 4 + v->NumVars * 16 + gridtimes * 16;
  1302. }
  1303. v->CompressMode = 1; /* one byte per grid point */
  1304. v->Projection = 1; /* Cylindrical equidistant */
  1305. v->FileVersion[0] = 0;
  1306. return 1;
  1307. }
  1308. /*
  1309. * Read a compressed grid from a COMP* file.
  1310. * Return: 1 = ok, 0 = error.
  1311. */
  1312. static int read_comp_grid(v5dstruct * v, int time, int var,
  1313. float *ga, float *gb, void *compdata)
  1314. {
  1315. unsigned int pos;
  1316. V5Dubyte bias;
  1317. int i, n, nl;
  1318. int f;
  1319. V5Dubyte *compdata1 = (V5Dubyte *) compdata;
  1320. f = v->FileDesc;
  1321. /* move to position in file */
  1322. pos = grid_position(v, time, var);
  1323. lseek(f, pos, SEEK_SET);
  1324. if (v->FileFormat == 0x80808083) {
  1325. /* read McIDAS grid and file numbers */
  1326. int mcfile, mcgrid;
  1327. read_int4(f, &mcfile);
  1328. read_int4(f, &mcgrid);
  1329. v->McFile[time][var] = (short)mcfile;
  1330. v->McGrid[time][var] = (short)mcgrid;
  1331. }
  1332. nl = v->Nl[var];
  1333. if (v->FileFormat == 0x80808080 || v->FileFormat == 0x80808081) {
  1334. /* single ga,gb pair for whole grid */
  1335. float a, b;
  1336. read_float4(f, &a);
  1337. read_float4(f, &b);
  1338. /* convert a, b to new v5d ga, gb values */
  1339. for (i = 0; i < nl; i++) {
  1340. if (a == 0.0) {
  1341. ga[i] = gb[i] = 0.0;
  1342. }
  1343. else {
  1344. gb[i] = (b + 128.0) / -a;
  1345. ga[i] = 1.0 / a;
  1346. }
  1347. }
  1348. bias = 128;
  1349. }
  1350. else {
  1351. /* read ga, gb arrays */
  1352. read_float4_array(f, ga, v->Nl[var]);
  1353. read_float4_array(f, gb, v->Nl[var]);
  1354. /* convert ga, gb values to v5d system */
  1355. for (i = 0; i < nl; i++) {
  1356. if (ga[i] == 0.0) {
  1357. ga[i] = gb[i] = 0.0;
  1358. }
  1359. else {
  1360. /*gb[i] = (gb[i]+125.0) / -ga[i]; */
  1361. gb[i] = (gb[i] + 128.0) / -ga[i];
  1362. ga[i] = 1.0 / ga[i];
  1363. }
  1364. }
  1365. bias = 128; /* 125 ??? */
  1366. }
  1367. /* read compressed grid data */
  1368. n = v->Nr * v->Nc * v->Nl[var];
  1369. if (read_bytes(f, compdata1, n) != n)
  1370. return 0;
  1371. /* convert data values to v5d system */
  1372. n = v->Nr * v->Nc * v->Nl[var];
  1373. for (i = 0; i < n; i++) {
  1374. compdata1[i] += bias;
  1375. }
  1376. return 1;
  1377. }
  1378. /*
  1379. * Read a v5d file header.
  1380. * Input: f - file opened for reading.
  1381. * v - pointer to v5dstruct to store header info into.
  1382. * Return: 1 = ok, 0 = error.
  1383. */
  1384. static int read_v5d_header(v5dstruct * v)
  1385. {
  1386. #define SKIP(N) lseek( f, N, SEEK_CUR )
  1387. int end_of_header = 0;
  1388. unsigned int id;
  1389. int idlen, var, numargs;
  1390. int f;
  1391. f = v->FileDesc;
  1392. /* first try to read the header id */
  1393. read_int4(f, (int *)&id);
  1394. read_int4(f, &idlen);
  1395. if (id == TAG_ID && idlen == 0) {
  1396. /* this is a v5d file */
  1397. v->FileFormat = 0;
  1398. }
  1399. else if (id >= 0x80808080 && id <= 0x80808083) {
  1400. /* this is an old COMP* file */
  1401. v->FileFormat = id;
  1402. return read_comp_header(f, v);
  1403. }
  1404. else {
  1405. /* unknown file type */
  1406. printf("Error: not a v5d file\n");
  1407. return 0;
  1408. }
  1409. v->CompressMode = 1; /* default */
  1410. while (!end_of_header) {
  1411. int tag, length;
  1412. int i, var, time, nl, lev;
  1413. if (read_int4(f, &tag) < 1 || read_int4(f, &length) < 1) {
  1414. printf("Error while reading header, premature EOF\n");
  1415. return 0;
  1416. }
  1417. switch (tag) {
  1418. case TAG_VERSION:
  1419. assert(length == 10);
  1420. read_bytes(f, v->FileVersion, 10);
  1421. /* Check if reading a file made by a future version of Vis5D */
  1422. if (strcmp(v->FileVersion, FILE_VERSION) > 0) {
  1423. G_warning
  1424. ("Trying to read a version %s file, you should upgrade Vis5D",
  1425. v->FileVersion);
  1426. }
  1427. break;
  1428. case TAG_NUMTIMES:
  1429. assert(length == 4);
  1430. read_int4(f, &v->NumTimes);
  1431. break;
  1432. case TAG_NUMVARS:
  1433. assert(length == 4);
  1434. read_int4(f, &v->NumVars);
  1435. break;
  1436. case TAG_VARNAME:
  1437. assert(length == 14); /* 1 int + 10 char */
  1438. read_int4(f, &var);
  1439. read_bytes(f, v->VarName[var], 10);
  1440. break;
  1441. case TAG_NR:
  1442. /* Number of rows for all variables */
  1443. assert(length == 4);
  1444. read_int4(f, &v->Nr);
  1445. break;
  1446. case TAG_NC:
  1447. /* Number of columns for all variables */
  1448. assert(length == 4);
  1449. read_int4(f, &v->Nc);
  1450. break;
  1451. case TAG_NL:
  1452. /* Number of levels for all variables */
  1453. assert(length == 4);
  1454. read_int4(f, &nl);
  1455. for (i = 0; i < v->NumVars; i++) {
  1456. v->Nl[i] = nl;
  1457. }
  1458. break;
  1459. case TAG_NL_VAR:
  1460. /* Number of levels for one variable */
  1461. assert(length == 8);
  1462. read_int4(f, &var);
  1463. read_int4(f, &v->Nl[var]);
  1464. break;
  1465. case TAG_LOWLEV_VAR:
  1466. /* Lowest level for one variable */
  1467. assert(length == 8);
  1468. read_int4(f, &var);
  1469. read_int4(f, &v->LowLev[var]);
  1470. break;
  1471. case TAG_TIME:
  1472. /* Time stamp for 1 timestep */
  1473. assert(length == 8);
  1474. read_int4(f, &time);
  1475. read_int4(f, &v->TimeStamp[time]);
  1476. break;
  1477. case TAG_DATE:
  1478. /* Date stamp for 1 timestep */
  1479. assert(length == 8);
  1480. read_int4(f, &time);
  1481. read_int4(f, &v->DateStamp[time]);
  1482. break;
  1483. case TAG_MINVAL:
  1484. /* Minimum value for a variable */
  1485. assert(length == 8);
  1486. read_int4(f, &var);
  1487. read_float4(f, &v->MinVal[var]);
  1488. break;
  1489. case TAG_MAXVAL:
  1490. /* Maximum value for a variable */
  1491. assert(length == 8);
  1492. read_int4(f, &var);
  1493. read_float4(f, &v->MaxVal[var]);
  1494. break;
  1495. case TAG_COMPRESS:
  1496. /* Compress mode */
  1497. assert(length == 4);
  1498. read_int4(f, &v->CompressMode);
  1499. break;
  1500. case TAG_UNITS:
  1501. /* physical units */
  1502. assert(length == 24);
  1503. read_int4(f, &var);
  1504. read_bytes(f, v->Units[var], 20);
  1505. break;
  1506. /*
  1507. * Vertical coordinate system
  1508. */
  1509. case TAG_VERTICAL_SYSTEM:
  1510. assert(length == 4);
  1511. read_int4(f, &v->VerticalSystem);
  1512. if (v->VerticalSystem < 0 || v->VerticalSystem > 3) {
  1513. printf("Error: bad vertical coordinate system: %d\n",
  1514. v->VerticalSystem);
  1515. }
  1516. break;
  1517. case TAG_VERT_ARGS:
  1518. read_int4(f, &numargs);
  1519. assert(numargs <= MAXVERTARGS);
  1520. read_float4_array(f, v->VertArgs, numargs);
  1521. assert(length == numargs * 4 + 4);
  1522. break;
  1523. case TAG_HEIGHT:
  1524. /* height of a grid level */
  1525. assert(length == 8);
  1526. read_int4(f, &lev);
  1527. read_float4(f, &v->VertArgs[lev]);
  1528. break;
  1529. case TAG_BOTTOMBOUND:
  1530. assert(length == 4);
  1531. read_float4(f, &v->VertArgs[0]);
  1532. break;
  1533. case TAG_LEVINC:
  1534. assert(length == 4);
  1535. read_float4(f, &v->VertArgs[1]);
  1536. break;
  1537. /*
  1538. * Map projection information
  1539. */
  1540. case TAG_PROJECTION:
  1541. assert(length == 4);
  1542. read_int4(f, &v->Projection);
  1543. if (v->Projection < 0 || v->Projection > 4) { /* WLH 4-21-95 */
  1544. printf("Error while reading header, bad projection (%d)\n",
  1545. v->Projection);
  1546. return 0;
  1547. }
  1548. break;
  1549. case TAG_PROJ_ARGS:
  1550. read_int4(f, &numargs);
  1551. assert(numargs <= MAXPROJARGS);
  1552. read_float4_array(f, v->ProjArgs, numargs);
  1553. assert(length == 4 * numargs + 4);
  1554. break;
  1555. case TAG_NORTHBOUND:
  1556. assert(length == 4);
  1557. if (v->Projection == 0 || v->Projection == 1 ||
  1558. v->Projection == 4) {
  1559. read_float4(f, &v->ProjArgs[0]);
  1560. }
  1561. else {
  1562. SKIP(4);
  1563. }
  1564. break;
  1565. case TAG_WESTBOUND:
  1566. assert(length == 4);
  1567. if (v->Projection == 0 || v->Projection == 1 ||
  1568. v->Projection == 4) {
  1569. read_float4(f, &v->ProjArgs[1]);
  1570. }
  1571. else {
  1572. SKIP(4);
  1573. }
  1574. break;
  1575. case TAG_ROWINC:
  1576. assert(length == 4);
  1577. if (v->Projection == 0 || v->Projection == 1 ||
  1578. v->Projection == 4) {
  1579. read_float4(f, &v->ProjArgs[2]);
  1580. }
  1581. else {
  1582. SKIP(4);
  1583. }
  1584. break;
  1585. case TAG_COLINC:
  1586. assert(length == 4);
  1587. if (v->Projection == 0 || v->Projection == 1 ||
  1588. v->Projection == 4) {
  1589. read_float4(f, &v->ProjArgs[3]);
  1590. }
  1591. else if (v->Projection == 2) {
  1592. read_float4(f, &v->ProjArgs[5]);
  1593. }
  1594. else if (v->Projection == 3) {
  1595. read_float4(f, &v->ProjArgs[4]);
  1596. }
  1597. else {
  1598. SKIP(4);
  1599. }
  1600. break;
  1601. case TAG_LAT1:
  1602. assert(length == 4);
  1603. if (v->Projection == 2) {
  1604. read_float4(f, &v->ProjArgs[0]);
  1605. }
  1606. else {
  1607. SKIP(4);
  1608. }
  1609. break;
  1610. case TAG_LAT2:
  1611. assert(length == 4);
  1612. if (v->Projection == 2) {
  1613. read_float4(f, &v->ProjArgs[1]);
  1614. }
  1615. else {
  1616. SKIP(4);
  1617. }
  1618. break;
  1619. case TAG_POLE_ROW:
  1620. assert(length == 4);
  1621. if (v->Projection == 2) {
  1622. read_float4(f, &v->ProjArgs[2]);
  1623. }
  1624. else {
  1625. SKIP(4);
  1626. }
  1627. break;
  1628. case TAG_POLE_COL:
  1629. assert(length == 4);
  1630. if (v->Projection == 2) {
  1631. read_float4(f, &v->ProjArgs[3]);
  1632. }
  1633. else {
  1634. SKIP(4);
  1635. }
  1636. break;
  1637. case TAG_CENTLON:
  1638. assert(length == 4);
  1639. if (v->Projection == 2) {
  1640. read_float4(f, &v->ProjArgs[4]);
  1641. }
  1642. else if (v->Projection == 3) {
  1643. read_float4(f, &v->ProjArgs[1]);
  1644. }
  1645. else if (v->Projection == 4) { /* WLH 4-21-95 */
  1646. read_float4(f, &v->ProjArgs[5]);
  1647. }
  1648. else {
  1649. SKIP(4);
  1650. }
  1651. break;
  1652. case TAG_CENTLAT:
  1653. assert(length == 4);
  1654. if (v->Projection == 3) {
  1655. read_float4(f, &v->ProjArgs[0]);
  1656. }
  1657. else if (v->Projection == 4) { /* WLH 4-21-95 */
  1658. read_float4(f, &v->ProjArgs[4]);
  1659. }
  1660. else {
  1661. SKIP(4);
  1662. }
  1663. break;
  1664. case TAG_CENTROW:
  1665. assert(length == 4);
  1666. if (v->Projection == 3) {
  1667. read_float4(f, &v->ProjArgs[2]);
  1668. }
  1669. else {
  1670. SKIP(4);
  1671. }
  1672. break;
  1673. case TAG_CENTCOL:
  1674. assert(length == 4);
  1675. if (v->Projection == 3) {
  1676. read_float4(f, &v->ProjArgs[3]);
  1677. }
  1678. else {
  1679. SKIP(4);
  1680. }
  1681. break;
  1682. case TAG_ROTATION:
  1683. assert(length == 4);
  1684. if (v->Projection == 4) { /* WLH 4-21-95 */
  1685. read_float4(f, &v->ProjArgs[6]);
  1686. }
  1687. else {
  1688. SKIP(4);
  1689. }
  1690. break;
  1691. case TAG_END:
  1692. /* end of header */
  1693. end_of_header = 1;
  1694. lseek(f, length, SEEK_CUR);
  1695. break;
  1696. default:
  1697. /* unknown tag, skip to next tag */
  1698. printf("Unknown tag: %d length=%d\n", tag, length);
  1699. lseek(f, length, SEEK_CUR);
  1700. break;
  1701. }
  1702. }
  1703. v5dVerifyStruct(v);
  1704. /* Now we're ready to read the grid data */
  1705. /* Save current file pointer */
  1706. v->FirstGridPos = ltell(f);
  1707. /* compute grid sizes */
  1708. v->SumGridSizes = 0;
  1709. for (var = 0; var < v->NumVars; var++) {
  1710. v->GridSize[var] = 8 * v->Nl[var] + v5dSizeofGrid(v, 0, var);
  1711. v->SumGridSizes += v->GridSize[var];
  1712. }
  1713. return 1;
  1714. #undef SKIP
  1715. }
  1716. /*
  1717. * Open a v5d file for reading.
  1718. * Input: filename - name of v5d file to open
  1719. * v - pointer to a v5dstruct in which to put header info or NULL
  1720. * if a struct should be dynamically allocated.
  1721. * Return: NULL if error, else v or a pointer to a new v5dstruct if v was NULL
  1722. */
  1723. v5dstruct *v5dOpenFile(const char *filename, v5dstruct * v)
  1724. {
  1725. int fd;
  1726. fd = open(filename, O_RDONLY);
  1727. if (fd == -1) {
  1728. /* error */
  1729. return 0;
  1730. }
  1731. if (v) {
  1732. v5dInitStruct(v);
  1733. }
  1734. else {
  1735. v = v5dNewStruct();
  1736. if (!v) {
  1737. return NULL;
  1738. }
  1739. }
  1740. v->FileDesc = fd;
  1741. v->Mode = 'r';
  1742. if (read_v5d_header(v)) {
  1743. return v;
  1744. }
  1745. else {
  1746. return NULL;
  1747. }
  1748. }
  1749. /*
  1750. * Read a compressed grid from a v5d file.
  1751. * Input: v - pointer to v5dstruct describing the file
  1752. * time, var - which timestep and variable
  1753. * ga, gb - arrays to store grid (de)compression values
  1754. * compdata - address of where to store compressed grid data.
  1755. * Return: 1 = ok, 0 = error.
  1756. */
  1757. int v5dReadCompressedGrid(v5dstruct * v, int time, int var,
  1758. float *ga, float *gb, void *compdata)
  1759. {
  1760. int n, k;
  1761. off_t pos;
  1762. if (time < 0 || time >= v->NumTimes) {
  1763. printf("Error in v5dReadCompressedGrid: bad timestep argument (%d)\n",
  1764. time);
  1765. return 0;
  1766. }
  1767. if (var < 0 || var >= v->NumVars) {
  1768. printf("Error in v5dReadCompressedGrid: bad var argument (%d)\n",
  1769. var);
  1770. return 0;
  1771. }
  1772. if (v->FileFormat) {
  1773. /* old COMP* file */
  1774. return read_comp_grid(v, time, var, ga, gb, compdata);
  1775. }
  1776. /* move to position in file */
  1777. pos = grid_position(v, time, var);
  1778. lseek(v->FileDesc, pos, SEEK_SET);
  1779. /* read ga, gb arrays */
  1780. read_float4_array(v->FileDesc, ga, v->Nl[var]);
  1781. read_float4_array(v->FileDesc, gb, v->Nl[var]);
  1782. /* read compressed grid data */
  1783. n = v->Nr * v->Nc * v->Nl[var];
  1784. if (v->CompressMode == 1) {
  1785. k = read_block(v->FileDesc, compdata, n, 1) == n;
  1786. }
  1787. else if (v->CompressMode == 2) {
  1788. k = read_block(v->FileDesc, compdata, n, 2) == n;
  1789. }
  1790. else if (v->CompressMode == 4) {
  1791. k = read_block(v->FileDesc, compdata, n, 4) == n;
  1792. }
  1793. if (!k) {
  1794. /* error */
  1795. printf("Error in v5dReadCompressedGrid: read failed, bad file?\n");
  1796. }
  1797. return k;
  1798. /*
  1799. n = v->Nr * v->Nc * v->Nl[var] * v->CompressMode;
  1800. if (read( v->FileDesc, compdata, n )==n)
  1801. return 1;
  1802. else
  1803. return 0;
  1804. */
  1805. }
  1806. /*
  1807. * Read a grid from a v5d file, decompress it and return it.
  1808. * Input: v - pointer to v5dstruct describing file header
  1809. * time, var - which timestep and variable.
  1810. * data - address of buffer to put grid data
  1811. * Output: data - the grid data
  1812. * Return: 1 = ok, 0 = error.
  1813. */
  1814. int v5dReadGrid(v5dstruct * v, int time, int var, float data[])
  1815. {
  1816. float ga[MAXLEVELS], gb[MAXLEVELS];
  1817. void *compdata;
  1818. int bytes;
  1819. if (time < 0 || time >= v->NumTimes) {
  1820. printf("Error in v5dReadGrid: bad timestep argument (%d)\n", time);
  1821. return 0;
  1822. }
  1823. if (var < 0 || var >= v->NumVars) {
  1824. printf("Error in v5dReadGrid: bad variable argument (%d)\n", var);
  1825. return 0;
  1826. }
  1827. /* allocate compdata buffer */
  1828. if (v->CompressMode == 1) {
  1829. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(unsigned char);
  1830. }
  1831. else if (v->CompressMode == 2) {
  1832. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(unsigned short);
  1833. }
  1834. else if (v->CompressMode == 4) {
  1835. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(float);
  1836. }
  1837. compdata = (void *)G_malloc(bytes);
  1838. if (!compdata) {
  1839. printf("Error in v5dReadGrid: out of memory (needed %d bytes)\n",
  1840. bytes);
  1841. return 0;
  1842. }
  1843. /* read the compressed data */
  1844. if (!v5dReadCompressedGrid(v, time, var, ga, gb, compdata)) {
  1845. return 0;
  1846. }
  1847. /* decompress the data */
  1848. v5dDecompressGrid(v->Nr, v->Nc, v->Nl[var], v->CompressMode,
  1849. compdata, ga, gb, data);
  1850. /* free compdata */
  1851. G_free(compdata);
  1852. return 1;
  1853. }
  1854. /**********************************************************************/
  1855. /***** Output Functions *****/
  1856. /**********************************************************************/
  1857. static int write_tag(v5dstruct * v, int tag, int length, int newfile)
  1858. {
  1859. if (!newfile) {
  1860. /* have to check that there's room in header to write this tagged item */
  1861. if (v->CurPos + 8 + length > v->FirstGridPos) {
  1862. printf("Error: out of header space!\n");
  1863. /* Out of header space! */
  1864. return 0;
  1865. }
  1866. }
  1867. if (write_int4(v->FileDesc, tag) == 0)
  1868. return 0;
  1869. if (write_int4(v->FileDesc, length) == 0)
  1870. return 0;
  1871. v->CurPos += 8 + length;
  1872. return 1;
  1873. }
  1874. /*
  1875. * Write the information in the given v5dstruct as a v5d file header.
  1876. * Note that the current file position is restored when this function
  1877. * returns normally.
  1878. * Input: f - file already open for writing
  1879. * v - pointer to v5dstruct
  1880. * Return: 1 = ok, 0 = error.
  1881. */
  1882. static int write_v5d_header(v5dstruct * v)
  1883. {
  1884. int var, time, maxnl;
  1885. off_t filler;
  1886. int f;
  1887. int newfile;
  1888. if (v->FileFormat != 0) {
  1889. printf("Error: v5d library can't write comp5d format files.\n");
  1890. return 0;
  1891. }
  1892. f = v->FileDesc;
  1893. if (!v5dVerifyStruct(v))
  1894. return 0;
  1895. /* Determine if we're writing to a new file */
  1896. if (v->FirstGridPos == 0) {
  1897. newfile = 1;
  1898. }
  1899. else {
  1900. newfile = 0;
  1901. }
  1902. /* compute grid sizes */
  1903. v->SumGridSizes = 0;
  1904. for (var = 0; var < v->NumVars; var++) {
  1905. v->GridSize[var] = 8 * v->Nl[var] + v5dSizeofGrid(v, 0, var);
  1906. v->SumGridSizes += v->GridSize[var];
  1907. }
  1908. /* set file pointer to start of file */
  1909. lseek(f, 0, SEEK_SET);
  1910. v->CurPos = 0;
  1911. /*
  1912. * Write the tagged header info
  1913. */
  1914. #define WRITE_TAG( V, T, L ) if (!write_tag(V,T,L,newfile)) return 0;
  1915. /* ID */
  1916. WRITE_TAG(v, TAG_ID, 0);
  1917. /* File Version */
  1918. WRITE_TAG(v, TAG_VERSION, 10);
  1919. write_bytes(f, FILE_VERSION, 10);
  1920. /* Number of timesteps */
  1921. WRITE_TAG(v, TAG_NUMTIMES, 4);
  1922. write_int4(f, v->NumTimes);
  1923. /* Number of variables */
  1924. WRITE_TAG(v, TAG_NUMVARS, 4);
  1925. write_int4(f, v->NumVars);
  1926. /* Names of variables */
  1927. for (var = 0; var < v->NumVars; var++) {
  1928. WRITE_TAG(v, TAG_VARNAME, 14);
  1929. write_int4(f, var);
  1930. write_bytes(f, v->VarName[var], 10);
  1931. }
  1932. /* Physical Units */
  1933. for (var = 0; var < v->NumVars; var++) {
  1934. WRITE_TAG(v, TAG_UNITS, 24);
  1935. write_int4(f, var);
  1936. write_bytes(f, v->Units[var], 20);
  1937. }
  1938. /* Date and time of each timestep */
  1939. for (time = 0; time < v->NumTimes; time++) {
  1940. WRITE_TAG(v, TAG_TIME, 8);
  1941. write_int4(f, time);
  1942. write_int4(f, v->TimeStamp[time]);
  1943. WRITE_TAG(v, TAG_DATE, 8);
  1944. write_int4(f, time);
  1945. write_int4(f, v->DateStamp[time]);
  1946. }
  1947. /* Number of rows */
  1948. WRITE_TAG(v, TAG_NR, 4);
  1949. write_int4(f, v->Nr);
  1950. /* Number of columns */
  1951. WRITE_TAG(v, TAG_NC, 4);
  1952. write_int4(f, v->Nc);
  1953. /* Number of levels, compute maxnl */
  1954. maxnl = 0;
  1955. for (var = 0; var < v->NumVars; var++) {
  1956. WRITE_TAG(v, TAG_NL_VAR, 8);
  1957. write_int4(f, var);
  1958. write_int4(f, v->Nl[var]);
  1959. WRITE_TAG(v, TAG_LOWLEV_VAR, 8);
  1960. write_int4(f, var);
  1961. write_int4(f, v->LowLev[var]);
  1962. if (v->Nl[var] + v->LowLev[var] > maxnl) {
  1963. maxnl = v->Nl[var] + v->LowLev[var];
  1964. }
  1965. }
  1966. /* Min/Max values */
  1967. for (var = 0; var < v->NumVars; var++) {
  1968. WRITE_TAG(v, TAG_MINVAL, 8);
  1969. write_int4(f, var);
  1970. write_float4(f, v->MinVal[var]);
  1971. WRITE_TAG(v, TAG_MAXVAL, 8);
  1972. write_int4(f, var);
  1973. write_float4(f, v->MaxVal[var]);
  1974. }
  1975. /* Compress mode */
  1976. WRITE_TAG(v, TAG_COMPRESS, 4);
  1977. write_int4(f, v->CompressMode);
  1978. /* Vertical Coordinate System */
  1979. WRITE_TAG(v, TAG_VERTICAL_SYSTEM, 4);
  1980. write_int4(f, v->VerticalSystem);
  1981. WRITE_TAG(v, TAG_VERT_ARGS, 4 + 4 * MAXVERTARGS);
  1982. write_int4(f, MAXVERTARGS);
  1983. write_float4_array(f, v->VertArgs, MAXVERTARGS);
  1984. /* Map Projection */
  1985. WRITE_TAG(v, TAG_PROJECTION, 4);
  1986. write_int4(f, v->Projection);
  1987. WRITE_TAG(v, TAG_PROJ_ARGS, 4 + 4 * MAXPROJARGS);
  1988. write_int4(f, MAXPROJARGS);
  1989. write_float4_array(f, v->ProjArgs, MAXPROJARGS);
  1990. /* write END tag */
  1991. if (newfile) {
  1992. /* We're writing to a brand new file. Reserve 10000 bytes */
  1993. /* for future header growth. */
  1994. WRITE_TAG(v, TAG_END, 10000);
  1995. lseek(f, 10000, SEEK_CUR);
  1996. /* Let file pointer indicate where first grid is stored */
  1997. v->FirstGridPos = ltell(f);
  1998. }
  1999. else {
  2000. /* we're rewriting a header */
  2001. filler = v->FirstGridPos - ltell(f);
  2002. WRITE_TAG(v, TAG_END, filler - 8);
  2003. }
  2004. #undef WRITE_TAG
  2005. return 1;
  2006. }
  2007. /*
  2008. * Open a v5d file for writing. If the named file already exists,
  2009. * it will be deleted.
  2010. * Input: filename - name of v5d file to create.
  2011. * v - pointer to v5dstruct with the header info to write.
  2012. * Return: 1 = ok, 0 = error.
  2013. */
  2014. int v5dCreateFile(const char *filename, v5dstruct * v)
  2015. {
  2016. mode_t mask;
  2017. int fd;
  2018. mask = 0666;
  2019. fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mask);
  2020. if (fd == -1) {
  2021. printf("Error in v5dCreateFile: open failed\n");
  2022. v->FileDesc = -1;
  2023. v->Mode = 0;
  2024. return 0;
  2025. }
  2026. else {
  2027. /* ok */
  2028. v->FileDesc = fd;
  2029. v->Mode = 'w';
  2030. /* write header and return status */
  2031. return write_v5d_header(v);
  2032. }
  2033. }
  2034. /*
  2035. * Open a v5d file for updating/appending and read the header info.
  2036. * Input: filename - name of v5d file to open for updating.
  2037. * v - pointer to v5dstruct in which the file header info will be
  2038. * put. If v is NULL a v5dstruct will be allocated and returned.
  2039. * Return: NULL if error, else v or a pointer to a new v5dstruct if v as NULL
  2040. */
  2041. v5dstruct *v5dUpdateFile(const char *filename, v5dstruct * v)
  2042. {
  2043. int fd;
  2044. fd = open(filename, O_RDWR);
  2045. if (fd == -1) {
  2046. return NULL;
  2047. }
  2048. if (!v) {
  2049. v = v5dNewStruct();
  2050. if (!v) {
  2051. return NULL;
  2052. }
  2053. }
  2054. v->FileDesc = fd;
  2055. v->Mode = 'w';
  2056. if (read_v5d_header(v)) {
  2057. return v;
  2058. }
  2059. else {
  2060. return NULL;
  2061. }
  2062. }
  2063. /*
  2064. * Write a compressed grid to a v5d file.
  2065. * Input: v - pointer to v5dstruct describing the file
  2066. * time, var - which timestep and variable
  2067. * ga, gb - the GA and GB (de)compression value arrays
  2068. * compdata - address of array of compressed data values
  2069. * Return: 1 = ok, 0 = error.
  2070. */
  2071. int v5dWriteCompressedGrid(const v5dstruct * v, int time, int var,
  2072. const float *ga, const float *gb,
  2073. const void *compdata)
  2074. {
  2075. int n, k;
  2076. off_t pos;
  2077. /* simple error checks */
  2078. if (v->Mode != 'w') {
  2079. printf("Error in v5dWriteCompressedGrid: file opened for reading,");
  2080. printf(" not writing.\n");
  2081. return 0;
  2082. }
  2083. if (time < 0 || time >= v->NumTimes) {
  2084. printf
  2085. ("Error in v5dWriteCompressedGrid: bad timestep argument (%d)\n",
  2086. time);
  2087. return 0;
  2088. }
  2089. if (var < 0 || var >= v->NumVars) {
  2090. printf
  2091. ("Error in v5dWriteCompressedGrid: bad variable argument (%d)\n",
  2092. var);
  2093. return 0;
  2094. }
  2095. /* move to position in file */
  2096. pos = grid_position(v, time, var);
  2097. if (lseek(v->FileDesc, pos, SEEK_SET) < 0) {
  2098. /* lseek failed, return error */
  2099. printf
  2100. ("Error in v5dWrite[Compressed]Grid: seek failed, disk full?\n");
  2101. return 0;
  2102. }
  2103. /* write ga, gb arrays */
  2104. k = 0;
  2105. if (write_float4_array(v->FileDesc, ga, v->Nl[var]) == v->Nl[var] &&
  2106. write_float4_array(v->FileDesc, gb, v->Nl[var]) == v->Nl[var]) {
  2107. /* write compressed grid data (k=1=OK, k=0=Error) */
  2108. n = v->Nr * v->Nc * v->Nl[var];
  2109. if (v->CompressMode == 1) {
  2110. k = write_block(v->FileDesc, compdata, n, 1) == n;
  2111. }
  2112. else if (v->CompressMode == 2) {
  2113. k = write_block(v->FileDesc, compdata, n, 2) == n;
  2114. }
  2115. else if (v->CompressMode == 4) {
  2116. k = write_block(v->FileDesc, compdata, n, 4) == n;
  2117. }
  2118. }
  2119. if (k == 0) {
  2120. /* Error while writing */
  2121. printf
  2122. ("Error in v5dWrite[Compressed]Grid: write failed, disk full?\n");
  2123. }
  2124. return k;
  2125. /*
  2126. n = v->Nr * v->Nc * v->Nl[var] * v->CompressMode;
  2127. if (write_bytes( v->FileDesc, compdata, n )!=n) {
  2128. printf("Error in v5dWrite[Compressed]Grid: write failed, disk full?\n");
  2129. return 0;
  2130. }
  2131. else {
  2132. return 1;
  2133. }
  2134. */
  2135. }
  2136. /*
  2137. * Compress a grid and write it to a v5d file.
  2138. * Input: v - pointer to v5dstruct describing the file
  2139. * time, var - which timestep and variable (starting at 0)
  2140. * data - address of uncompressed grid data
  2141. * Return: 1 = ok, 0 = error.
  2142. */
  2143. int v5dWriteGrid(v5dstruct * v, int time, int var, const float data[])
  2144. {
  2145. float ga[MAXLEVELS], gb[MAXLEVELS];
  2146. void *compdata;
  2147. int n, bytes;
  2148. float min, max;
  2149. if (v->Mode != 'w') {
  2150. printf("Error in v5dWriteGrid: file opened for reading,");
  2151. printf(" not writing.\n");
  2152. return 0;
  2153. }
  2154. if (time < 0 || time >= v->NumTimes) {
  2155. printf("Error in v5dWriteGrid: bad timestep argument (%d)\n", time);
  2156. return 0;
  2157. }
  2158. if (var < 0 || var >= v->NumVars) {
  2159. printf("Error in v5dWriteGrid: bad variable argument (%d)\n", var);
  2160. return 0;
  2161. }
  2162. /* allocate compdata buffer */
  2163. if (v->CompressMode == 1) {
  2164. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(unsigned char);
  2165. }
  2166. else if (v->CompressMode == 2) {
  2167. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(unsigned short);
  2168. }
  2169. else if (v->CompressMode == 4) {
  2170. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(float);
  2171. }
  2172. compdata = (void *)G_malloc(bytes);
  2173. if (!compdata) {
  2174. printf("Error in v5dWriteGrid: out of memory (needed %d bytes)\n",
  2175. bytes);
  2176. return 0;
  2177. }
  2178. /* compress the grid data */
  2179. v5dCompressGrid(v->Nr, v->Nc, v->Nl[var], v->CompressMode, data,
  2180. compdata, ga, gb, &min, &max);
  2181. /* update min and max value */
  2182. if (min < v->MinVal[var])
  2183. v->MinVal[var] = min;
  2184. if (max > v->MaxVal[var])
  2185. v->MaxVal[var] = max;
  2186. /* write the compressed grid */
  2187. n = v5dWriteCompressedGrid(v, time, var, ga, gb, compdata);
  2188. /* free compdata */
  2189. G_free(compdata);
  2190. return n;
  2191. }
  2192. /*
  2193. * Close a v5d file which was opened with open_v5d_file() or
  2194. * create_v5d_file().
  2195. * Input: f - file descriptor
  2196. * Return: 1 = ok, 0 = error
  2197. */
  2198. int v5dCloseFile(v5dstruct * v)
  2199. {
  2200. int status = 1;
  2201. if (v->Mode == 'w') {
  2202. /* rewrite header because writing grids updates the minval and */
  2203. /* maxval fields */
  2204. lseek(v->FileDesc, 0, SEEK_SET);
  2205. status = write_v5d_header(v);
  2206. lseek(v->FileDesc, 0, SEEK_END);
  2207. close(v->FileDesc);
  2208. }
  2209. else if (v->Mode == 'r') {
  2210. /* just close the file */
  2211. close(v->FileDesc);
  2212. }
  2213. else {
  2214. printf("Error in v5dCloseFile: bad v5dstruct argument\n");
  2215. return 0;
  2216. }
  2217. v->FileDesc = -1;
  2218. v->Mode = 0;
  2219. return status;
  2220. }
  2221. /**********************************************************************/
  2222. /***** Simple v5d file writing functions. *****/
  2223. /**********************************************************************/
  2224. static v5dstruct *Simple = NULL;
  2225. /*
  2226. * Create a new v5d file specifying both a map projection and vertical
  2227. * coordinate system. See README file for argument details.
  2228. * Return: 1 = ok, 0 = error.
  2229. */
  2230. int v5dCreate(const char *name, int numtimes, int numvars,
  2231. int nr, int nc, const int nl[],
  2232. const char varname[MAXVARS][10],
  2233. const int timestamp[], const int datestamp[],
  2234. int compressmode,
  2235. int projection,
  2236. const float proj_args[], int vertical, const float vert_args[])
  2237. {
  2238. int var, time, maxnl, i;
  2239. /* initialize the v5dstruct */
  2240. Simple = v5dNewStruct();
  2241. Simple->NumTimes = numtimes;
  2242. Simple->NumVars = numvars;
  2243. Simple->Nr = nr;
  2244. Simple->Nc = nc;
  2245. maxnl = nl[0];
  2246. for (var = 0; var < numvars; var++) {
  2247. if (nl[var] > maxnl) {
  2248. maxnl = nl[var];
  2249. }
  2250. Simple->Nl[var] = nl[var];
  2251. Simple->LowLev[var] = 0;
  2252. strncpy(Simple->VarName[var], varname[var], 10);
  2253. Simple->VarName[var][9] = 0;
  2254. }
  2255. /* time and date for each timestep */
  2256. for (time = 0; time < numtimes; time++) {
  2257. Simple->TimeStamp[time] = timestamp[time];
  2258. Simple->DateStamp[time] = datestamp[time];
  2259. }
  2260. Simple->CompressMode = compressmode;
  2261. /* Map projection and vertical coordinate system */
  2262. Simple->Projection = projection;
  2263. memcpy(Simple->ProjArgs, proj_args, MAXPROJARGS * sizeof(float));
  2264. Simple->VerticalSystem = vertical;
  2265. if (vertical == 3) {
  2266. /* convert pressures to heights */
  2267. for (i = 0; i < MAXVERTARGS; i++) {
  2268. if (vert_args[i] > 0.000001) {
  2269. Simple->VertArgs[i] = pressure_to_height(vert_args[i]);
  2270. }
  2271. else
  2272. Simple->VertArgs[i] = 0.0;
  2273. }
  2274. }
  2275. else {
  2276. memcpy(Simple->VertArgs, vert_args, MAXVERTARGS * sizeof(float));
  2277. }
  2278. /* create the file */
  2279. if (v5dCreateFile(name, Simple) == 0) {
  2280. printf("Error in v5dCreateSimpleFile: unable to create %s\n", name);
  2281. return 0;
  2282. }
  2283. else {
  2284. return 1;
  2285. }
  2286. }
  2287. /*
  2288. * Create a new v5d file using minimal information.
  2289. * Return: 1 = ok, 0 = error. See README file for argument details.
  2290. */
  2291. int v5dCreateSimple(const char *name, int numtimes, int numvars,
  2292. int nr, int nc, int nl,
  2293. const char varname[MAXVARS][10],
  2294. const int timestamp[], const int datestamp[],
  2295. float northlat, float latinc,
  2296. float westlon, float loninc,
  2297. float bottomhgt, float hgtinc)
  2298. {
  2299. int nlvar[MAXVARS];
  2300. int compressmode, projection, vertical;
  2301. float proj_args[100], vert_args[MAXLEVELS];
  2302. int i;
  2303. for (i = 0; i < numvars; i++) {
  2304. nlvar[i] = nl;
  2305. }
  2306. compressmode = 1;
  2307. projection = 1;
  2308. proj_args[0] = northlat;
  2309. proj_args[1] = westlon;
  2310. proj_args[2] = latinc;
  2311. proj_args[3] = loninc;
  2312. vertical = 1;
  2313. vert_args[0] = bottomhgt;
  2314. vert_args[1] = hgtinc;
  2315. return v5dCreate(name, numtimes, numvars, nr, nc, nlvar,
  2316. varname, timestamp, datestamp, compressmode,
  2317. projection, proj_args, vertical, vert_args);
  2318. }
  2319. /*
  2320. * Set lowest levels for each variable (other than default of 0).
  2321. * Input: lowlev - array [NumVars] of ints
  2322. * Return: 1 = ok, 0 = error
  2323. */
  2324. int v5dSetLowLev(int lowlev[])
  2325. {
  2326. int var;
  2327. if (Simple) {
  2328. for (var = 0; var < Simple->NumVars; var++) {
  2329. Simple->LowLev[var] = lowlev[var];
  2330. }
  2331. return 1;
  2332. }
  2333. else {
  2334. printf("Error: must call v5dCreate before v5dSetLowLev\n");
  2335. return 0;
  2336. }
  2337. }
  2338. /*
  2339. * Set the units for a variable.
  2340. * Input: var - a variable in [1,NumVars]
  2341. * units - a string
  2342. * Return: 1 = ok, 0 = error
  2343. */
  2344. int v5dSetUnits(int var, const char *units)
  2345. {
  2346. if (Simple) {
  2347. if (var >= 1 && var <= Simple->NumVars) {
  2348. strncpy(Simple->Units[var - 1], units, 19);
  2349. Simple->Units[var - 1][19] = 0;
  2350. return 1;
  2351. }
  2352. else {
  2353. printf("Error: bad variable number in v5dSetUnits\n");
  2354. return 0;
  2355. }
  2356. }
  2357. else {
  2358. printf("Error: must call v5dCreate before v5dSetUnits\n");
  2359. return 0;
  2360. }
  2361. }
  2362. /*
  2363. * Write a grid to a v5d file.
  2364. * Input: time - timestep in [1,NumTimes]
  2365. * var - timestep in [1,NumVars]
  2366. * data - array [nr*nc*nl] of floats
  2367. * Return: 1 = ok, 0 = error
  2368. */
  2369. int v5dWrite(int time, int var, const float data[])
  2370. {
  2371. if (Simple) {
  2372. if (time < 1 || time > Simple->NumTimes) {
  2373. printf("Error in v5dWrite: bad timestep number: %d\n", time);
  2374. return 0;
  2375. }
  2376. if (var < 1 || var > Simple->NumVars) {
  2377. printf("Error in v5dWrite: bad variable number: %d\n", var);
  2378. }
  2379. return v5dWriteGrid(Simple, time - 1, var - 1, data);
  2380. }
  2381. else {
  2382. printf("Error: must call v5dCreate before v5dWrite\n");
  2383. return 0;
  2384. }
  2385. }
  2386. /*
  2387. * Close a v5d file after the last grid has been written to it.
  2388. * Return: 1 = ok, 0 = error
  2389. */
  2390. int v5dClose(void)
  2391. {
  2392. if (Simple) {
  2393. int ok = v5dCloseFile(Simple);
  2394. v5dFreeStruct(Simple);
  2395. return ok;
  2396. }
  2397. else {
  2398. printf("Error: v5dClose: no file to close\n");
  2399. return 0;
  2400. }
  2401. }
  2402. /**********************************************************************/
  2403. /***** FORTRAN-callable simple output *****/
  2404. /**********************************************************************/
  2405. /*
  2406. * Create a v5d file. See README file for argument descriptions.
  2407. * Return: 1 = ok, 0 = error.
  2408. */
  2409. #ifdef UNDERSCORE
  2410. int v5dcreate_
  2411. #else
  2412. # ifdef _CRAY
  2413. int V5DCREATE
  2414. # else
  2415. int v5dcreate
  2416. # endif
  2417. #endif
  2418. (const char *name, const int *numtimes, const int *numvars,
  2419. const int *nr, const int *nc, const int nl[],
  2420. const char varname[][10],
  2421. const int timestamp[], const int datestamp[],
  2422. const int *compressmode,
  2423. const int *projection,
  2424. const float proj_args[], const int *vertical, const float vert_args[])
  2425. {
  2426. char filename[100];
  2427. char names[MAXVARS][10];
  2428. int i, maxnl, args;
  2429. /* copy name to filename and remove trailing spaces if any */
  2430. copy_string(filename, name, 100);
  2431. /*
  2432. * Check for uninitialized arguments
  2433. */
  2434. if (*numtimes < 1) {
  2435. printf("Error: numtimes invalid\n");
  2436. return 0;
  2437. }
  2438. if (*numvars < 1) {
  2439. printf("Error: numvars invalid\n");
  2440. return 0;
  2441. }
  2442. if (*nr < 2) {
  2443. printf("Error: nr invalid\n");
  2444. return 0;
  2445. }
  2446. if (*nc < 2) {
  2447. printf("Error: nc invalid\n");
  2448. return 0;
  2449. }
  2450. maxnl = 0;
  2451. for (i = 0; i < *numvars; i++) {
  2452. if (nl[i] < 1) {
  2453. printf("Error: nl(%d) invalid\n", i + 1);
  2454. return 0;
  2455. }
  2456. if (nl[i] > maxnl) {
  2457. maxnl = nl[i];
  2458. }
  2459. }
  2460. for (i = 0; i < *numvars; i++) {
  2461. if (copy_string2(names[i], varname[i], 10) == 0) {
  2462. printf("Error: uninitialized varname(%d)\n", i + 1);
  2463. return 0;
  2464. }
  2465. }
  2466. for (i = 0; i < *numtimes; i++) {
  2467. if (timestamp[i] < 0) {
  2468. printf("Error: times(%d) invalid\n", i + 1);
  2469. return 0;
  2470. }
  2471. if (datestamp[i] < 0) {
  2472. printf("Error: dates(%d) invalid\n", i + 1);
  2473. return 0;
  2474. }
  2475. }
  2476. if (*compressmode != 1 && *compressmode != 2 && *compressmode != 4) {
  2477. printf("Error: compressmode invalid\n");
  2478. return 0;
  2479. }
  2480. switch (*projection) {
  2481. case 0:
  2482. args = 4;
  2483. break;
  2484. case 1:
  2485. args = 0;
  2486. if (IS_MISSING(proj_args[0])) {
  2487. printf("Error: northlat (proj_args(1)) invalid\n");
  2488. return 0;
  2489. }
  2490. if (IS_MISSING(proj_args[1])) {
  2491. printf("Error: westlon (proj_args(2)) invalid\n");
  2492. return 0;
  2493. }
  2494. if (IS_MISSING(proj_args[2])) {
  2495. printf("Error: latinc (proj_args(3)) invalid\n");
  2496. return 0;
  2497. }
  2498. if (IS_MISSING(proj_args[3])) {
  2499. printf("Error: loninc (proj_args(4)) invalid\n");
  2500. return 0;
  2501. }
  2502. break;
  2503. case 2:
  2504. args = 6;
  2505. break;
  2506. case 3:
  2507. args = 5;
  2508. break;
  2509. case 4:
  2510. args = 7;
  2511. break;
  2512. default:
  2513. args = 0;
  2514. printf("Error: projection invalid\n");
  2515. return 0;
  2516. }
  2517. for (i = 0; i < args; i++) {
  2518. if (IS_MISSING(proj_args[i])) {
  2519. printf("Error: proj_args(%d) invalid\n", i + 1);
  2520. return 0;
  2521. }
  2522. }
  2523. switch (*vertical) {
  2524. case 0:
  2525. /* WLH 31 Oct 96 - just fall through
  2526. args = 4;
  2527. break;
  2528. */
  2529. case 1:
  2530. args = 0;
  2531. if (IS_MISSING(vert_args[0])) {
  2532. printf("Error: bottomhgt (vert_args(1)) invalid\n");
  2533. return 0;
  2534. }
  2535. if (IS_MISSING(vert_args[1])) {
  2536. printf("Error: hgtinc (vert_args(2)) invalid\n");
  2537. return 0;
  2538. }
  2539. break;
  2540. case 2:
  2541. case 3:
  2542. args = maxnl;
  2543. break;
  2544. default:
  2545. args = 0;
  2546. printf("Error: vertical invalid\n");
  2547. return 0;
  2548. }
  2549. for (i = 0; i < args; i++) {
  2550. if (IS_MISSING(vert_args[i])) {
  2551. printf("Error: vert_args(%d) invalid\n", i + 1);
  2552. return 0;
  2553. }
  2554. }
  2555. return v5dCreate(filename, *numtimes, *numvars, *nr, *nc, nl,
  2556. (const char (*)[10])names, timestamp, datestamp,
  2557. *compressmode,
  2558. *projection, proj_args, *vertical, vert_args);
  2559. }
  2560. /*
  2561. * Create a simple v5d file. See README file for argument descriptions.
  2562. * Return: 1 = ok, 0 = error.
  2563. */
  2564. #ifdef UNDERSCORE
  2565. int v5dcreatesimple_
  2566. #else
  2567. # ifdef _CRAY
  2568. int V5DCREATESIMPLE
  2569. # else
  2570. int v5dcreatesimple
  2571. # endif
  2572. #endif
  2573. (const char *name, const int *numtimes, const int *numvars,
  2574. const int *nr, const int *nc, const int *nl,
  2575. const char varname[][10],
  2576. const int timestamp[], const int datestamp[],
  2577. const float *northlat, const float *latinc,
  2578. const float *westlon, const float *loninc,
  2579. const float *bottomhgt, const float *hgtinc)
  2580. {
  2581. int compressmode, projection, vertical;
  2582. float projarg[100], vertarg[MAXLEVELS];
  2583. int varnl[MAXVARS];
  2584. int i;
  2585. for (i = 0; i < MAXVARS; i++) {
  2586. varnl[i] = *nl;
  2587. }
  2588. compressmode = 1;
  2589. projection = 1;
  2590. projarg[0] = *northlat;
  2591. projarg[1] = *westlon;
  2592. projarg[2] = *latinc;
  2593. projarg[3] = *loninc;
  2594. vertical = 1;
  2595. vertarg[0] = *bottomhgt;
  2596. vertarg[1] = *hgtinc;
  2597. #ifdef UNDERSCORE
  2598. return v5dcreate_
  2599. #else
  2600. # ifdef _CRAY
  2601. return V5DCREATE
  2602. # else
  2603. return v5dcreate
  2604. # endif
  2605. #endif
  2606. (name, numtimes, numvars, nr, nc, varnl,
  2607. varname, timestamp, datestamp, &compressmode,
  2608. &projection, projarg, &vertical, vertarg);
  2609. }
  2610. /*
  2611. * Set lowest levels for each variable (other than default of 0).
  2612. * Input: lowlev - array [NumVars] of ints
  2613. * Return: 1 = ok, 0 = error
  2614. */
  2615. #ifdef UNDERSCORE
  2616. int v5dsetlowlev_
  2617. #else
  2618. # ifdef _CRAY
  2619. int V5DSETLOWLEV
  2620. # else
  2621. int v5dsetlowlev
  2622. # endif
  2623. #endif
  2624. (int *lowlev)
  2625. {
  2626. return v5dSetLowLev(lowlev);
  2627. }
  2628. /*
  2629. * Set the units for a variable.
  2630. * Input: var - variable number in [1,NumVars]
  2631. * units - a character string
  2632. * Return: 1 = ok, 0 = error
  2633. */
  2634. #ifdef UNDERSCORE
  2635. int v5dsetunits_
  2636. #else
  2637. # ifdef _CRAY
  2638. int V5DSETUNITS
  2639. # else
  2640. int v5dsetunits
  2641. # endif
  2642. #endif
  2643. (int *var, char *name)
  2644. {
  2645. return v5dSetUnits(*var, name);
  2646. }
  2647. /*
  2648. * Write a grid of data to the file.
  2649. * Input: time - timestep in [1,NumTimes]
  2650. * var - timestep in [1,NumVars]
  2651. * data - array [nr*nc*nl] of floats
  2652. * Return: 1 = ok, 0 = error
  2653. */
  2654. #ifdef UNDERSCORE
  2655. int v5dwrite_
  2656. #else
  2657. # ifdef _CRAY
  2658. int V5DWRITE
  2659. # else
  2660. int v5dwrite
  2661. # endif
  2662. #endif
  2663. (const int *time, const int *var, const float *data)
  2664. {
  2665. return v5dWrite(*time, *var, data);
  2666. }
  2667. /*
  2668. * Specify the McIDAS GR3D file number and grid number which correspond
  2669. * to the grid specified by time and var.
  2670. * Input: time, var - timestep and variable of grid (starting at 1)
  2671. * mcfile, mcgrid - McIDAS grid file number and grid number
  2672. * Return: 1 = ok, 0 = errror (bad time or var)
  2673. */
  2674. #ifdef UNDERSCORE
  2675. int v5dmcfile_
  2676. #else
  2677. # ifdef _CRAY
  2678. int V5DMCFILE
  2679. # else
  2680. int v5dmcfile
  2681. # endif
  2682. #endif
  2683. (const int *time, const int *var, const int *mcfile, const int *mcgrid)
  2684. {
  2685. if (*time < 1 || *time > Simple->NumTimes) {
  2686. printf("Bad time argument to v5dSetMcIDASgrid: %d\n", *time);
  2687. return 0;
  2688. }
  2689. if (*var < 1 || *var > Simple->NumVars) {
  2690. printf("Bad var argument to v5dSetMcIDASgrid: %d\n", *var);
  2691. return 0;
  2692. }
  2693. Simple->McFile[*time - 1][*var - 1] = (short)*mcfile;
  2694. Simple->McGrid[*time - 1][*var - 1] = (short)*mcgrid;
  2695. return 1;
  2696. }
  2697. /*
  2698. * Close a simple v5d file.
  2699. */
  2700. #ifdef UNDERSCORE
  2701. int v5dclose_(void)
  2702. #else
  2703. # ifdef _CRAY
  2704. int V5DCLOSE(void)
  2705. # else
  2706. int v5dclose(void)
  2707. # endif
  2708. #endif
  2709. {
  2710. return v5dClose();
  2711. }