v5d.c 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151
  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 int 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 = (((off_t)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;
  1217. off_t gridsize;
  1218. int it, iv, nl, i, j;
  1219. float delta;
  1220. read_int4(f, &gridtimes);
  1221. read_int4(f, &v->NumVars);
  1222. read_int4(f, &v->NumTimes);
  1223. read_int4(f, &v->Nr);
  1224. read_int4(f, &v->Nc);
  1225. read_int4(f, &nl);
  1226. for (i = 0; i < v->NumVars; i++) {
  1227. v->Nl[i] = nl;
  1228. }
  1229. read_float4(f, &v->ProjArgs[2]);
  1230. read_float4(f, &v->ProjArgs[3]);
  1231. /* Read height and determine if equal spacing */
  1232. v->VerticalSystem = 1;
  1233. for (i = 0; i < nl; i++) {
  1234. read_float4(f, &v->VertArgs[i]);
  1235. if (i == 1) {
  1236. delta = v->VertArgs[1] - v->VertArgs[0];
  1237. }
  1238. else if (i > 1) {
  1239. if (delta != (v->VertArgs[i] - v->VertArgs[i - 1])) {
  1240. v->VerticalSystem = 2;
  1241. }
  1242. }
  1243. }
  1244. if (v->VerticalSystem == 1) {
  1245. v->VertArgs[1] = delta;
  1246. }
  1247. /* read variable names */
  1248. for (iv = 0; iv < v->NumVars; iv++) {
  1249. char name[8];
  1250. read_bytes(f, name, 8);
  1251. /* remove trailing spaces, if any */
  1252. for (j = 7; j > 0; j--) {
  1253. if (name[j] == ' ' || name[j] == 0)
  1254. name[j] = 0;
  1255. else
  1256. break;
  1257. }
  1258. strncpy(v->VarName[iv], name, 8);
  1259. v->VarName[iv][8] = 0;
  1260. }
  1261. for (iv = 0; iv < v->NumVars; iv++) {
  1262. read_float4(f, &v->MinVal[iv]);
  1263. }
  1264. for (iv = 0; iv < v->NumVars; iv++) {
  1265. read_float4(f, &v->MaxVal[iv]);
  1266. }
  1267. for (it = 0; it < gridtimes; it++) {
  1268. read_int4(f, &j);
  1269. v->TimeStamp[it] = v5dSecondsToHHMMSS(j);
  1270. }
  1271. for (it = 0; it < gridtimes; it++) {
  1272. read_int4(f, &j);
  1273. v->DateStamp[it] = v5dDaysToYYDDD(j);
  1274. }
  1275. for (it = 0; it < gridtimes; it++) {
  1276. float nlat;
  1277. read_float4(f, &nlat);
  1278. if (it == 0)
  1279. v->ProjArgs[0] = nlat;
  1280. }
  1281. for (it = 0; it < gridtimes; it++) {
  1282. float wlon;
  1283. read_float4(f, &wlon);
  1284. if (it == 0)
  1285. v->ProjArgs[1] = wlon;
  1286. }
  1287. /* calculate grid storage sizes */
  1288. if (id == 0x80808082) {
  1289. gridsize = nl * 2 * 4 + (((off_t)v->Nr * v->Nc * nl + 3) / 4) * 4;
  1290. }
  1291. else {
  1292. /* McIDAS grid and file numbers present */
  1293. gridsize = 8 + nl * 2 * 4 + ((v->Nr * v->Nc * nl + 3) / 4) * 4;
  1294. }
  1295. for (i = 0; i < v->NumVars; i++) {
  1296. v->GridSize[i] = gridsize;
  1297. }
  1298. v->SumGridSizes = gridsize * v->NumVars;
  1299. /* read McIDAS numbers??? */
  1300. /* size (in bytes) of all header info */
  1301. v->FirstGridPos =
  1302. 9 * 4 + v->Nl[0] * 4 + v->NumVars * 16 + gridtimes * 16;
  1303. }
  1304. v->CompressMode = 1; /* one byte per grid point */
  1305. v->Projection = 1; /* Cylindrical equidistant */
  1306. v->FileVersion[0] = 0;
  1307. return 1;
  1308. }
  1309. /*
  1310. * Read a compressed grid from a COMP* file.
  1311. * Return: 1 = ok, 0 = error.
  1312. */
  1313. static int read_comp_grid(v5dstruct * v, int time, int var,
  1314. float *ga, float *gb, void *compdata)
  1315. {
  1316. unsigned int pos;
  1317. V5Dubyte bias;
  1318. int i, n, nl;
  1319. int f;
  1320. V5Dubyte *compdata1 = (V5Dubyte *) compdata;
  1321. f = v->FileDesc;
  1322. /* move to position in file */
  1323. pos = grid_position(v, time, var);
  1324. lseek(f, pos, SEEK_SET);
  1325. if (v->FileFormat == 0x80808083) {
  1326. /* read McIDAS grid and file numbers */
  1327. int mcfile, mcgrid;
  1328. read_int4(f, &mcfile);
  1329. read_int4(f, &mcgrid);
  1330. v->McFile[time][var] = (short)mcfile;
  1331. v->McGrid[time][var] = (short)mcgrid;
  1332. }
  1333. nl = v->Nl[var];
  1334. if (v->FileFormat == 0x80808080 || v->FileFormat == 0x80808081) {
  1335. /* single ga,gb pair for whole grid */
  1336. float a, b;
  1337. read_float4(f, &a);
  1338. read_float4(f, &b);
  1339. /* convert a, b to new v5d ga, gb values */
  1340. for (i = 0; i < nl; i++) {
  1341. if (a == 0.0) {
  1342. ga[i] = gb[i] = 0.0;
  1343. }
  1344. else {
  1345. gb[i] = (b + 128.0) / -a;
  1346. ga[i] = 1.0 / a;
  1347. }
  1348. }
  1349. bias = 128;
  1350. }
  1351. else {
  1352. /* read ga, gb arrays */
  1353. read_float4_array(f, ga, v->Nl[var]);
  1354. read_float4_array(f, gb, v->Nl[var]);
  1355. /* convert ga, gb values to v5d system */
  1356. for (i = 0; i < nl; i++) {
  1357. if (ga[i] == 0.0) {
  1358. ga[i] = gb[i] = 0.0;
  1359. }
  1360. else {
  1361. /*gb[i] = (gb[i]+125.0) / -ga[i]; */
  1362. gb[i] = (gb[i] + 128.0) / -ga[i];
  1363. ga[i] = 1.0 / ga[i];
  1364. }
  1365. }
  1366. bias = 128; /* 125 ??? */
  1367. }
  1368. /* read compressed grid data */
  1369. n = v->Nr * v->Nc * v->Nl[var];
  1370. if (read_bytes(f, compdata1, n) != n)
  1371. return 0;
  1372. /* convert data values to v5d system */
  1373. n = v->Nr * v->Nc * v->Nl[var];
  1374. for (i = 0; i < n; i++) {
  1375. compdata1[i] += bias;
  1376. }
  1377. return 1;
  1378. }
  1379. /*
  1380. * Read a v5d file header.
  1381. * Input: f - file opened for reading.
  1382. * v - pointer to v5dstruct to store header info into.
  1383. * Return: 1 = ok, 0 = error.
  1384. */
  1385. static int read_v5d_header(v5dstruct * v)
  1386. {
  1387. #define SKIP(N) lseek( f, N, SEEK_CUR )
  1388. int end_of_header = 0;
  1389. unsigned int id;
  1390. int idlen, var, numargs;
  1391. int f;
  1392. f = v->FileDesc;
  1393. /* first try to read the header id */
  1394. read_int4(f, (int *)&id);
  1395. read_int4(f, &idlen);
  1396. if (id == TAG_ID && idlen == 0) {
  1397. /* this is a v5d file */
  1398. v->FileFormat = 0;
  1399. }
  1400. else if (id >= 0x80808080 && id <= 0x80808083) {
  1401. /* this is an old COMP* file */
  1402. v->FileFormat = id;
  1403. return read_comp_header(f, v);
  1404. }
  1405. else {
  1406. /* unknown file type */
  1407. printf("Error: not a v5d file\n");
  1408. return 0;
  1409. }
  1410. v->CompressMode = 1; /* default */
  1411. while (!end_of_header) {
  1412. int tag, length;
  1413. int i, var, time, nl, lev;
  1414. if (read_int4(f, &tag) < 1 || read_int4(f, &length) < 1) {
  1415. printf("Error while reading header, premature EOF\n");
  1416. return 0;
  1417. }
  1418. switch (tag) {
  1419. case TAG_VERSION:
  1420. assert(length == 10);
  1421. read_bytes(f, v->FileVersion, 10);
  1422. /* Check if reading a file made by a future version of Vis5D */
  1423. if (strcmp(v->FileVersion, FILE_VERSION) > 0) {
  1424. G_warning
  1425. ("Trying to read a version %s file, you should upgrade Vis5D",
  1426. v->FileVersion);
  1427. }
  1428. break;
  1429. case TAG_NUMTIMES:
  1430. assert(length == 4);
  1431. read_int4(f, &v->NumTimes);
  1432. break;
  1433. case TAG_NUMVARS:
  1434. assert(length == 4);
  1435. read_int4(f, &v->NumVars);
  1436. break;
  1437. case TAG_VARNAME:
  1438. assert(length == 14); /* 1 int + 10 char */
  1439. read_int4(f, &var);
  1440. read_bytes(f, v->VarName[var], 10);
  1441. break;
  1442. case TAG_NR:
  1443. /* Number of rows for all variables */
  1444. assert(length == 4);
  1445. read_int4(f, &v->Nr);
  1446. break;
  1447. case TAG_NC:
  1448. /* Number of columns for all variables */
  1449. assert(length == 4);
  1450. read_int4(f, &v->Nc);
  1451. break;
  1452. case TAG_NL:
  1453. /* Number of levels for all variables */
  1454. assert(length == 4);
  1455. read_int4(f, &nl);
  1456. for (i = 0; i < v->NumVars; i++) {
  1457. v->Nl[i] = nl;
  1458. }
  1459. break;
  1460. case TAG_NL_VAR:
  1461. /* Number of levels for one variable */
  1462. assert(length == 8);
  1463. read_int4(f, &var);
  1464. read_int4(f, &v->Nl[var]);
  1465. break;
  1466. case TAG_LOWLEV_VAR:
  1467. /* Lowest level for one variable */
  1468. assert(length == 8);
  1469. read_int4(f, &var);
  1470. read_int4(f, &v->LowLev[var]);
  1471. break;
  1472. case TAG_TIME:
  1473. /* Time stamp for 1 timestep */
  1474. assert(length == 8);
  1475. read_int4(f, &time);
  1476. read_int4(f, &v->TimeStamp[time]);
  1477. break;
  1478. case TAG_DATE:
  1479. /* Date stamp for 1 timestep */
  1480. assert(length == 8);
  1481. read_int4(f, &time);
  1482. read_int4(f, &v->DateStamp[time]);
  1483. break;
  1484. case TAG_MINVAL:
  1485. /* Minimum value for a variable */
  1486. assert(length == 8);
  1487. read_int4(f, &var);
  1488. read_float4(f, &v->MinVal[var]);
  1489. break;
  1490. case TAG_MAXVAL:
  1491. /* Maximum value for a variable */
  1492. assert(length == 8);
  1493. read_int4(f, &var);
  1494. read_float4(f, &v->MaxVal[var]);
  1495. break;
  1496. case TAG_COMPRESS:
  1497. /* Compress mode */
  1498. assert(length == 4);
  1499. read_int4(f, &v->CompressMode);
  1500. break;
  1501. case TAG_UNITS:
  1502. /* physical units */
  1503. assert(length == 24);
  1504. read_int4(f, &var);
  1505. read_bytes(f, v->Units[var], 20);
  1506. break;
  1507. /*
  1508. * Vertical coordinate system
  1509. */
  1510. case TAG_VERTICAL_SYSTEM:
  1511. assert(length == 4);
  1512. read_int4(f, &v->VerticalSystem);
  1513. if (v->VerticalSystem < 0 || v->VerticalSystem > 3) {
  1514. printf("Error: bad vertical coordinate system: %d\n",
  1515. v->VerticalSystem);
  1516. }
  1517. break;
  1518. case TAG_VERT_ARGS:
  1519. read_int4(f, &numargs);
  1520. assert(numargs <= MAXVERTARGS);
  1521. read_float4_array(f, v->VertArgs, numargs);
  1522. assert(length == numargs * 4 + 4);
  1523. break;
  1524. case TAG_HEIGHT:
  1525. /* height of a grid level */
  1526. assert(length == 8);
  1527. read_int4(f, &lev);
  1528. read_float4(f, &v->VertArgs[lev]);
  1529. break;
  1530. case TAG_BOTTOMBOUND:
  1531. assert(length == 4);
  1532. read_float4(f, &v->VertArgs[0]);
  1533. break;
  1534. case TAG_LEVINC:
  1535. assert(length == 4);
  1536. read_float4(f, &v->VertArgs[1]);
  1537. break;
  1538. /*
  1539. * Map projection information
  1540. */
  1541. case TAG_PROJECTION:
  1542. assert(length == 4);
  1543. read_int4(f, &v->Projection);
  1544. if (v->Projection < 0 || v->Projection > 4) { /* WLH 4-21-95 */
  1545. printf("Error while reading header, bad projection (%d)\n",
  1546. v->Projection);
  1547. return 0;
  1548. }
  1549. break;
  1550. case TAG_PROJ_ARGS:
  1551. read_int4(f, &numargs);
  1552. assert(numargs <= MAXPROJARGS);
  1553. read_float4_array(f, v->ProjArgs, numargs);
  1554. assert(length == 4 * numargs + 4);
  1555. break;
  1556. case TAG_NORTHBOUND:
  1557. assert(length == 4);
  1558. if (v->Projection == 0 || v->Projection == 1 ||
  1559. v->Projection == 4) {
  1560. read_float4(f, &v->ProjArgs[0]);
  1561. }
  1562. else {
  1563. SKIP(4);
  1564. }
  1565. break;
  1566. case TAG_WESTBOUND:
  1567. assert(length == 4);
  1568. if (v->Projection == 0 || v->Projection == 1 ||
  1569. v->Projection == 4) {
  1570. read_float4(f, &v->ProjArgs[1]);
  1571. }
  1572. else {
  1573. SKIP(4);
  1574. }
  1575. break;
  1576. case TAG_ROWINC:
  1577. assert(length == 4);
  1578. if (v->Projection == 0 || v->Projection == 1 ||
  1579. v->Projection == 4) {
  1580. read_float4(f, &v->ProjArgs[2]);
  1581. }
  1582. else {
  1583. SKIP(4);
  1584. }
  1585. break;
  1586. case TAG_COLINC:
  1587. assert(length == 4);
  1588. if (v->Projection == 0 || v->Projection == 1 ||
  1589. v->Projection == 4) {
  1590. read_float4(f, &v->ProjArgs[3]);
  1591. }
  1592. else if (v->Projection == 2) {
  1593. read_float4(f, &v->ProjArgs[5]);
  1594. }
  1595. else if (v->Projection == 3) {
  1596. read_float4(f, &v->ProjArgs[4]);
  1597. }
  1598. else {
  1599. SKIP(4);
  1600. }
  1601. break;
  1602. case TAG_LAT1:
  1603. assert(length == 4);
  1604. if (v->Projection == 2) {
  1605. read_float4(f, &v->ProjArgs[0]);
  1606. }
  1607. else {
  1608. SKIP(4);
  1609. }
  1610. break;
  1611. case TAG_LAT2:
  1612. assert(length == 4);
  1613. if (v->Projection == 2) {
  1614. read_float4(f, &v->ProjArgs[1]);
  1615. }
  1616. else {
  1617. SKIP(4);
  1618. }
  1619. break;
  1620. case TAG_POLE_ROW:
  1621. assert(length == 4);
  1622. if (v->Projection == 2) {
  1623. read_float4(f, &v->ProjArgs[2]);
  1624. }
  1625. else {
  1626. SKIP(4);
  1627. }
  1628. break;
  1629. case TAG_POLE_COL:
  1630. assert(length == 4);
  1631. if (v->Projection == 2) {
  1632. read_float4(f, &v->ProjArgs[3]);
  1633. }
  1634. else {
  1635. SKIP(4);
  1636. }
  1637. break;
  1638. case TAG_CENTLON:
  1639. assert(length == 4);
  1640. if (v->Projection == 2) {
  1641. read_float4(f, &v->ProjArgs[4]);
  1642. }
  1643. else if (v->Projection == 3) {
  1644. read_float4(f, &v->ProjArgs[1]);
  1645. }
  1646. else if (v->Projection == 4) { /* WLH 4-21-95 */
  1647. read_float4(f, &v->ProjArgs[5]);
  1648. }
  1649. else {
  1650. SKIP(4);
  1651. }
  1652. break;
  1653. case TAG_CENTLAT:
  1654. assert(length == 4);
  1655. if (v->Projection == 3) {
  1656. read_float4(f, &v->ProjArgs[0]);
  1657. }
  1658. else if (v->Projection == 4) { /* WLH 4-21-95 */
  1659. read_float4(f, &v->ProjArgs[4]);
  1660. }
  1661. else {
  1662. SKIP(4);
  1663. }
  1664. break;
  1665. case TAG_CENTROW:
  1666. assert(length == 4);
  1667. if (v->Projection == 3) {
  1668. read_float4(f, &v->ProjArgs[2]);
  1669. }
  1670. else {
  1671. SKIP(4);
  1672. }
  1673. break;
  1674. case TAG_CENTCOL:
  1675. assert(length == 4);
  1676. if (v->Projection == 3) {
  1677. read_float4(f, &v->ProjArgs[3]);
  1678. }
  1679. else {
  1680. SKIP(4);
  1681. }
  1682. break;
  1683. case TAG_ROTATION:
  1684. assert(length == 4);
  1685. if (v->Projection == 4) { /* WLH 4-21-95 */
  1686. read_float4(f, &v->ProjArgs[6]);
  1687. }
  1688. else {
  1689. SKIP(4);
  1690. }
  1691. break;
  1692. case TAG_END:
  1693. /* end of header */
  1694. end_of_header = 1;
  1695. lseek(f, length, SEEK_CUR);
  1696. break;
  1697. default:
  1698. /* unknown tag, skip to next tag */
  1699. printf("Unknown tag: %d length=%d\n", tag, length);
  1700. lseek(f, length, SEEK_CUR);
  1701. break;
  1702. }
  1703. }
  1704. v5dVerifyStruct(v);
  1705. /* Now we're ready to read the grid data */
  1706. /* Save current file pointer */
  1707. v->FirstGridPos = ltell(f);
  1708. /* compute grid sizes */
  1709. v->SumGridSizes = 0;
  1710. for (var = 0; var < v->NumVars; var++) {
  1711. v->GridSize[var] = 8 * v->Nl[var] + v5dSizeofGrid(v, 0, var);
  1712. v->SumGridSizes += v->GridSize[var];
  1713. }
  1714. return 1;
  1715. #undef SKIP
  1716. }
  1717. /*
  1718. * Open a v5d file for reading.
  1719. * Input: filename - name of v5d file to open
  1720. * v - pointer to a v5dstruct in which to put header info or NULL
  1721. * if a struct should be dynamically allocated.
  1722. * Return: NULL if error, else v or a pointer to a new v5dstruct if v was NULL
  1723. */
  1724. v5dstruct *v5dOpenFile(const char *filename, v5dstruct * v)
  1725. {
  1726. int fd;
  1727. fd = open(filename, O_RDONLY);
  1728. if (fd == -1) {
  1729. /* error */
  1730. return 0;
  1731. }
  1732. if (v) {
  1733. v5dInitStruct(v);
  1734. }
  1735. else {
  1736. v = v5dNewStruct();
  1737. if (!v) {
  1738. return NULL;
  1739. }
  1740. }
  1741. v->FileDesc = fd;
  1742. v->Mode = 'r';
  1743. if (read_v5d_header(v)) {
  1744. return v;
  1745. }
  1746. else {
  1747. return NULL;
  1748. }
  1749. }
  1750. /*
  1751. * Read a compressed grid from a v5d file.
  1752. * Input: v - pointer to v5dstruct describing the file
  1753. * time, var - which timestep and variable
  1754. * ga, gb - arrays to store grid (de)compression values
  1755. * compdata - address of where to store compressed grid data.
  1756. * Return: 1 = ok, 0 = error.
  1757. */
  1758. int v5dReadCompressedGrid(v5dstruct * v, int time, int var,
  1759. float *ga, float *gb, void *compdata)
  1760. {
  1761. int pos, n, k;
  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, filler, maxnl;
  1885. int f;
  1886. int newfile;
  1887. if (v->FileFormat != 0) {
  1888. printf("Error: v5d library can't write comp5d format files.\n");
  1889. return 0;
  1890. }
  1891. f = v->FileDesc;
  1892. if (!v5dVerifyStruct(v))
  1893. return 0;
  1894. /* Determine if we're writing to a new file */
  1895. if (v->FirstGridPos == 0) {
  1896. newfile = 1;
  1897. }
  1898. else {
  1899. newfile = 0;
  1900. }
  1901. /* compute grid sizes */
  1902. v->SumGridSizes = 0;
  1903. for (var = 0; var < v->NumVars; var++) {
  1904. v->GridSize[var] = 8 * v->Nl[var] + v5dSizeofGrid(v, 0, var);
  1905. v->SumGridSizes += v->GridSize[var];
  1906. }
  1907. /* set file pointer to start of file */
  1908. lseek(f, 0, SEEK_SET);
  1909. v->CurPos = 0;
  1910. /*
  1911. * Write the tagged header info
  1912. */
  1913. #define WRITE_TAG( V, T, L ) if (!write_tag(V,T,L,newfile)) return 0;
  1914. /* ID */
  1915. WRITE_TAG(v, TAG_ID, 0);
  1916. /* File Version */
  1917. WRITE_TAG(v, TAG_VERSION, 10);
  1918. write_bytes(f, FILE_VERSION, 10);
  1919. /* Number of timesteps */
  1920. WRITE_TAG(v, TAG_NUMTIMES, 4);
  1921. write_int4(f, v->NumTimes);
  1922. /* Number of variables */
  1923. WRITE_TAG(v, TAG_NUMVARS, 4);
  1924. write_int4(f, v->NumVars);
  1925. /* Names of variables */
  1926. for (var = 0; var < v->NumVars; var++) {
  1927. WRITE_TAG(v, TAG_VARNAME, 14);
  1928. write_int4(f, var);
  1929. write_bytes(f, v->VarName[var], 10);
  1930. }
  1931. /* Physical Units */
  1932. for (var = 0; var < v->NumVars; var++) {
  1933. WRITE_TAG(v, TAG_UNITS, 24);
  1934. write_int4(f, var);
  1935. write_bytes(f, v->Units[var], 20);
  1936. }
  1937. /* Date and time of each timestep */
  1938. for (time = 0; time < v->NumTimes; time++) {
  1939. WRITE_TAG(v, TAG_TIME, 8);
  1940. write_int4(f, time);
  1941. write_int4(f, v->TimeStamp[time]);
  1942. WRITE_TAG(v, TAG_DATE, 8);
  1943. write_int4(f, time);
  1944. write_int4(f, v->DateStamp[time]);
  1945. }
  1946. /* Number of rows */
  1947. WRITE_TAG(v, TAG_NR, 4);
  1948. write_int4(f, v->Nr);
  1949. /* Number of columns */
  1950. WRITE_TAG(v, TAG_NC, 4);
  1951. write_int4(f, v->Nc);
  1952. /* Number of levels, compute maxnl */
  1953. maxnl = 0;
  1954. for (var = 0; var < v->NumVars; var++) {
  1955. WRITE_TAG(v, TAG_NL_VAR, 8);
  1956. write_int4(f, var);
  1957. write_int4(f, v->Nl[var]);
  1958. WRITE_TAG(v, TAG_LOWLEV_VAR, 8);
  1959. write_int4(f, var);
  1960. write_int4(f, v->LowLev[var]);
  1961. if (v->Nl[var] + v->LowLev[var] > maxnl) {
  1962. maxnl = v->Nl[var] + v->LowLev[var];
  1963. }
  1964. }
  1965. /* Min/Max values */
  1966. for (var = 0; var < v->NumVars; var++) {
  1967. WRITE_TAG(v, TAG_MINVAL, 8);
  1968. write_int4(f, var);
  1969. write_float4(f, v->MinVal[var]);
  1970. WRITE_TAG(v, TAG_MAXVAL, 8);
  1971. write_int4(f, var);
  1972. write_float4(f, v->MaxVal[var]);
  1973. }
  1974. /* Compress mode */
  1975. WRITE_TAG(v, TAG_COMPRESS, 4);
  1976. write_int4(f, v->CompressMode);
  1977. /* Vertical Coordinate System */
  1978. WRITE_TAG(v, TAG_VERTICAL_SYSTEM, 4);
  1979. write_int4(f, v->VerticalSystem);
  1980. WRITE_TAG(v, TAG_VERT_ARGS, 4 + 4 * MAXVERTARGS);
  1981. write_int4(f, MAXVERTARGS);
  1982. write_float4_array(f, v->VertArgs, MAXVERTARGS);
  1983. /* Map Projection */
  1984. WRITE_TAG(v, TAG_PROJECTION, 4);
  1985. write_int4(f, v->Projection);
  1986. WRITE_TAG(v, TAG_PROJ_ARGS, 4 + 4 * MAXPROJARGS);
  1987. write_int4(f, MAXPROJARGS);
  1988. write_float4_array(f, v->ProjArgs, MAXPROJARGS);
  1989. /* write END tag */
  1990. if (newfile) {
  1991. /* We're writing to a brand new file. Reserve 10000 bytes */
  1992. /* for future header growth. */
  1993. WRITE_TAG(v, TAG_END, 10000);
  1994. lseek(f, 10000, SEEK_CUR);
  1995. /* Let file pointer indicate where first grid is stored */
  1996. v->FirstGridPos = ltell(f);
  1997. }
  1998. else {
  1999. /* we're rewriting a header */
  2000. filler = v->FirstGridPos - ltell(f);
  2001. WRITE_TAG(v, TAG_END, filler - 8);
  2002. }
  2003. #undef WRITE_TAG
  2004. return 1;
  2005. }
  2006. /*
  2007. * Open a v5d file for writing. If the named file already exists,
  2008. * it will be deleted.
  2009. * Input: filename - name of v5d file to create.
  2010. * v - pointer to v5dstruct with the header info to write.
  2011. * Return: 1 = ok, 0 = error.
  2012. */
  2013. int v5dCreateFile(const char *filename, v5dstruct * v)
  2014. {
  2015. mode_t mask;
  2016. int fd;
  2017. mask = 0666;
  2018. fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mask);
  2019. if (fd == -1) {
  2020. printf("Error in v5dCreateFile: open failed\n");
  2021. v->FileDesc = -1;
  2022. v->Mode = 0;
  2023. return 0;
  2024. }
  2025. else {
  2026. /* ok */
  2027. v->FileDesc = fd;
  2028. v->Mode = 'w';
  2029. /* write header and return status */
  2030. return write_v5d_header(v);
  2031. }
  2032. }
  2033. /*
  2034. * Open a v5d file for updating/appending and read the header info.
  2035. * Input: filename - name of v5d file to open for updating.
  2036. * v - pointer to v5dstruct in which the file header info will be
  2037. * put. If v is NULL a v5dstruct will be allocated and returned.
  2038. * Return: NULL if error, else v or a pointer to a new v5dstruct if v as NULL
  2039. */
  2040. v5dstruct *v5dUpdateFile(const char *filename, v5dstruct * v)
  2041. {
  2042. int fd;
  2043. fd = open(filename, O_RDWR);
  2044. if (fd == -1) {
  2045. return NULL;
  2046. }
  2047. if (!v) {
  2048. v = v5dNewStruct();
  2049. if (!v) {
  2050. return NULL;
  2051. }
  2052. }
  2053. v->FileDesc = fd;
  2054. v->Mode = 'w';
  2055. if (read_v5d_header(v)) {
  2056. return v;
  2057. }
  2058. else {
  2059. return NULL;
  2060. }
  2061. }
  2062. /*
  2063. * Write a compressed grid to a v5d file.
  2064. * Input: v - pointer to v5dstruct describing the file
  2065. * time, var - which timestep and variable
  2066. * ga, gb - the GA and GB (de)compression value arrays
  2067. * compdata - address of array of compressed data values
  2068. * Return: 1 = ok, 0 = error.
  2069. */
  2070. int v5dWriteCompressedGrid(const v5dstruct * v, int time, int var,
  2071. const float *ga, const float *gb,
  2072. const void *compdata)
  2073. {
  2074. int pos, n, k;
  2075. /* simple error checks */
  2076. if (v->Mode != 'w') {
  2077. printf("Error in v5dWriteCompressedGrid: file opened for reading,");
  2078. printf(" not writing.\n");
  2079. return 0;
  2080. }
  2081. if (time < 0 || time >= v->NumTimes) {
  2082. printf
  2083. ("Error in v5dWriteCompressedGrid: bad timestep argument (%d)\n",
  2084. time);
  2085. return 0;
  2086. }
  2087. if (var < 0 || var >= v->NumVars) {
  2088. printf
  2089. ("Error in v5dWriteCompressedGrid: bad variable argument (%d)\n",
  2090. var);
  2091. return 0;
  2092. }
  2093. /* move to position in file */
  2094. pos = grid_position(v, time, var);
  2095. if (lseek(v->FileDesc, pos, SEEK_SET) < 0) {
  2096. /* lseek failed, return error */
  2097. printf
  2098. ("Error in v5dWrite[Compressed]Grid: seek failed, disk full?\n");
  2099. return 0;
  2100. }
  2101. /* write ga, gb arrays */
  2102. k = 0;
  2103. if (write_float4_array(v->FileDesc, ga, v->Nl[var]) == v->Nl[var] &&
  2104. write_float4_array(v->FileDesc, gb, v->Nl[var]) == v->Nl[var]) {
  2105. /* write compressed grid data (k=1=OK, k=0=Error) */
  2106. n = v->Nr * v->Nc * v->Nl[var];
  2107. if (v->CompressMode == 1) {
  2108. k = write_block(v->FileDesc, compdata, n, 1) == n;
  2109. }
  2110. else if (v->CompressMode == 2) {
  2111. k = write_block(v->FileDesc, compdata, n, 2) == n;
  2112. }
  2113. else if (v->CompressMode == 4) {
  2114. k = write_block(v->FileDesc, compdata, n, 4) == n;
  2115. }
  2116. }
  2117. if (k == 0) {
  2118. /* Error while writing */
  2119. printf
  2120. ("Error in v5dWrite[Compressed]Grid: write failed, disk full?\n");
  2121. }
  2122. return k;
  2123. /*
  2124. n = v->Nr * v->Nc * v->Nl[var] * v->CompressMode;
  2125. if (write_bytes( v->FileDesc, compdata, n )!=n) {
  2126. printf("Error in v5dWrite[Compressed]Grid: write failed, disk full?\n");
  2127. return 0;
  2128. }
  2129. else {
  2130. return 1;
  2131. }
  2132. */
  2133. }
  2134. /*
  2135. * Compress a grid and write it to a v5d file.
  2136. * Input: v - pointer to v5dstruct describing the file
  2137. * time, var - which timestep and variable (starting at 0)
  2138. * data - address of uncompressed grid data
  2139. * Return: 1 = ok, 0 = error.
  2140. */
  2141. int v5dWriteGrid(v5dstruct * v, int time, int var, const float data[])
  2142. {
  2143. float ga[MAXLEVELS], gb[MAXLEVELS];
  2144. void *compdata;
  2145. int n, bytes;
  2146. float min, max;
  2147. if (v->Mode != 'w') {
  2148. printf("Error in v5dWriteGrid: file opened for reading,");
  2149. printf(" not writing.\n");
  2150. return 0;
  2151. }
  2152. if (time < 0 || time >= v->NumTimes) {
  2153. printf("Error in v5dWriteGrid: bad timestep argument (%d)\n", time);
  2154. return 0;
  2155. }
  2156. if (var < 0 || var >= v->NumVars) {
  2157. printf("Error in v5dWriteGrid: bad variable argument (%d)\n", var);
  2158. return 0;
  2159. }
  2160. /* allocate compdata buffer */
  2161. if (v->CompressMode == 1) {
  2162. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(unsigned char);
  2163. }
  2164. else if (v->CompressMode == 2) {
  2165. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(unsigned short);
  2166. }
  2167. else if (v->CompressMode == 4) {
  2168. bytes = v->Nr * v->Nc * v->Nl[var] * (int)sizeof(float);
  2169. }
  2170. compdata = (void *)G_malloc(bytes);
  2171. if (!compdata) {
  2172. printf("Error in v5dWriteGrid: out of memory (needed %d bytes)\n",
  2173. bytes);
  2174. return 0;
  2175. }
  2176. /* compress the grid data */
  2177. v5dCompressGrid(v->Nr, v->Nc, v->Nl[var], v->CompressMode, data,
  2178. compdata, ga, gb, &min, &max);
  2179. /* update min and max value */
  2180. if (min < v->MinVal[var])
  2181. v->MinVal[var] = min;
  2182. if (max > v->MaxVal[var])
  2183. v->MaxVal[var] = max;
  2184. /* write the compressed grid */
  2185. n = v5dWriteCompressedGrid(v, time, var, ga, gb, compdata);
  2186. /* free compdata */
  2187. G_free(compdata);
  2188. return n;
  2189. }
  2190. /*
  2191. * Close a v5d file which was opened with open_v5d_file() or
  2192. * create_v5d_file().
  2193. * Input: f - file descriptor
  2194. * Return: 1 = ok, 0 = error
  2195. */
  2196. int v5dCloseFile(v5dstruct * v)
  2197. {
  2198. int status = 1;
  2199. if (v->Mode == 'w') {
  2200. /* rewrite header because writing grids updates the minval and */
  2201. /* maxval fields */
  2202. lseek(v->FileDesc, 0, SEEK_SET);
  2203. status = write_v5d_header(v);
  2204. lseek(v->FileDesc, 0, SEEK_END);
  2205. close(v->FileDesc);
  2206. }
  2207. else if (v->Mode == 'r') {
  2208. /* just close the file */
  2209. close(v->FileDesc);
  2210. }
  2211. else {
  2212. printf("Error in v5dCloseFile: bad v5dstruct argument\n");
  2213. return 0;
  2214. }
  2215. v->FileDesc = -1;
  2216. v->Mode = 0;
  2217. return status;
  2218. }
  2219. /**********************************************************************/
  2220. /***** Simple v5d file writing functions. *****/
  2221. /**********************************************************************/
  2222. static v5dstruct *Simple = NULL;
  2223. /*
  2224. * Create a new v5d file specifying both a map projection and vertical
  2225. * coordinate system. See README file for argument details.
  2226. * Return: 1 = ok, 0 = error.
  2227. */
  2228. int v5dCreate(const char *name, int numtimes, int numvars,
  2229. int nr, int nc, const int nl[],
  2230. const char varname[MAXVARS][10],
  2231. const int timestamp[], const int datestamp[],
  2232. int compressmode,
  2233. int projection,
  2234. const float proj_args[], int vertical, const float vert_args[])
  2235. {
  2236. int var, time, maxnl, i;
  2237. /* initialize the v5dstruct */
  2238. Simple = v5dNewStruct();
  2239. Simple->NumTimes = numtimes;
  2240. Simple->NumVars = numvars;
  2241. Simple->Nr = nr;
  2242. Simple->Nc = nc;
  2243. maxnl = nl[0];
  2244. for (var = 0; var < numvars; var++) {
  2245. if (nl[var] > maxnl) {
  2246. maxnl = nl[var];
  2247. }
  2248. Simple->Nl[var] = nl[var];
  2249. Simple->LowLev[var] = 0;
  2250. strncpy(Simple->VarName[var], varname[var], 10);
  2251. Simple->VarName[var][9] = 0;
  2252. }
  2253. /* time and date for each timestep */
  2254. for (time = 0; time < numtimes; time++) {
  2255. Simple->TimeStamp[time] = timestamp[time];
  2256. Simple->DateStamp[time] = datestamp[time];
  2257. }
  2258. Simple->CompressMode = compressmode;
  2259. /* Map projection and vertical coordinate system */
  2260. Simple->Projection = projection;
  2261. memcpy(Simple->ProjArgs, proj_args, MAXPROJARGS * sizeof(float));
  2262. Simple->VerticalSystem = vertical;
  2263. if (vertical == 3) {
  2264. /* convert pressures to heights */
  2265. for (i = 0; i < MAXVERTARGS; i++) {
  2266. if (vert_args[i] > 0.000001) {
  2267. Simple->VertArgs[i] = pressure_to_height(vert_args[i]);
  2268. }
  2269. else
  2270. Simple->VertArgs[i] = 0.0;
  2271. }
  2272. }
  2273. else {
  2274. memcpy(Simple->VertArgs, vert_args, MAXVERTARGS * sizeof(float));
  2275. }
  2276. /* create the file */
  2277. if (v5dCreateFile(name, Simple) == 0) {
  2278. printf("Error in v5dCreateSimpleFile: unable to create %s\n", name);
  2279. return 0;
  2280. }
  2281. else {
  2282. return 1;
  2283. }
  2284. }
  2285. /*
  2286. * Create a new v5d file using minimal information.
  2287. * Return: 1 = ok, 0 = error. See README file for argument details.
  2288. */
  2289. int v5dCreateSimple(const char *name, int numtimes, int numvars,
  2290. int nr, int nc, int nl,
  2291. const char varname[MAXVARS][10],
  2292. const int timestamp[], const int datestamp[],
  2293. float northlat, float latinc,
  2294. float westlon, float loninc,
  2295. float bottomhgt, float hgtinc)
  2296. {
  2297. int nlvar[MAXVARS];
  2298. int compressmode, projection, vertical;
  2299. float proj_args[100], vert_args[MAXLEVELS];
  2300. int i;
  2301. for (i = 0; i < numvars; i++) {
  2302. nlvar[i] = nl;
  2303. }
  2304. compressmode = 1;
  2305. projection = 1;
  2306. proj_args[0] = northlat;
  2307. proj_args[1] = westlon;
  2308. proj_args[2] = latinc;
  2309. proj_args[3] = loninc;
  2310. vertical = 1;
  2311. vert_args[0] = bottomhgt;
  2312. vert_args[1] = hgtinc;
  2313. return v5dCreate(name, numtimes, numvars, nr, nc, nlvar,
  2314. varname, timestamp, datestamp, compressmode,
  2315. projection, proj_args, vertical, vert_args);
  2316. }
  2317. /*
  2318. * Set lowest levels for each variable (other than default of 0).
  2319. * Input: lowlev - array [NumVars] of ints
  2320. * Return: 1 = ok, 0 = error
  2321. */
  2322. int v5dSetLowLev(int lowlev[])
  2323. {
  2324. int var;
  2325. if (Simple) {
  2326. for (var = 0; var < Simple->NumVars; var++) {
  2327. Simple->LowLev[var] = lowlev[var];
  2328. }
  2329. return 1;
  2330. }
  2331. else {
  2332. printf("Error: must call v5dCreate before v5dSetLowLev\n");
  2333. return 0;
  2334. }
  2335. }
  2336. /*
  2337. * Set the units for a variable.
  2338. * Input: var - a variable in [1,NumVars]
  2339. * units - a string
  2340. * Return: 1 = ok, 0 = error
  2341. */
  2342. int v5dSetUnits(int var, const char *units)
  2343. {
  2344. if (Simple) {
  2345. if (var >= 1 && var <= Simple->NumVars) {
  2346. strncpy(Simple->Units[var - 1], units, 19);
  2347. Simple->Units[var - 1][19] = 0;
  2348. return 1;
  2349. }
  2350. else {
  2351. printf("Error: bad variable number in v5dSetUnits\n");
  2352. return 0;
  2353. }
  2354. }
  2355. else {
  2356. printf("Error: must call v5dCreate before v5dSetUnits\n");
  2357. return 0;
  2358. }
  2359. }
  2360. /*
  2361. * Write a grid to a v5d file.
  2362. * Input: time - timestep in [1,NumTimes]
  2363. * var - timestep in [1,NumVars]
  2364. * data - array [nr*nc*nl] of floats
  2365. * Return: 1 = ok, 0 = error
  2366. */
  2367. int v5dWrite(int time, int var, const float data[])
  2368. {
  2369. if (Simple) {
  2370. if (time < 1 || time > Simple->NumTimes) {
  2371. printf("Error in v5dWrite: bad timestep number: %d\n", time);
  2372. return 0;
  2373. }
  2374. if (var < 1 || var > Simple->NumVars) {
  2375. printf("Error in v5dWrite: bad variable number: %d\n", var);
  2376. }
  2377. return v5dWriteGrid(Simple, time - 1, var - 1, data);
  2378. }
  2379. else {
  2380. printf("Error: must call v5dCreate before v5dWrite\n");
  2381. return 0;
  2382. }
  2383. }
  2384. /*
  2385. * Close a v5d file after the last grid has been written to it.
  2386. * Return: 1 = ok, 0 = error
  2387. */
  2388. int v5dClose(void)
  2389. {
  2390. if (Simple) {
  2391. int ok = v5dCloseFile(Simple);
  2392. v5dFreeStruct(Simple);
  2393. return ok;
  2394. }
  2395. else {
  2396. printf("Error: v5dClose: no file to close\n");
  2397. return 0;
  2398. }
  2399. }
  2400. /**********************************************************************/
  2401. /***** FORTRAN-callable simple output *****/
  2402. /**********************************************************************/
  2403. /*
  2404. * Create a v5d file. See README file for argument descriptions.
  2405. * Return: 1 = ok, 0 = error.
  2406. */
  2407. #ifdef UNDERSCORE
  2408. int v5dcreate_
  2409. #else
  2410. # ifdef _CRAY
  2411. int V5DCREATE
  2412. # else
  2413. int v5dcreate
  2414. # endif
  2415. #endif
  2416. (const char *name, const int *numtimes, const int *numvars,
  2417. const int *nr, const int *nc, const int nl[],
  2418. const char varname[][10],
  2419. const int timestamp[], const int datestamp[],
  2420. const int *compressmode,
  2421. const int *projection,
  2422. const float proj_args[], const int *vertical, const float vert_args[])
  2423. {
  2424. char filename[100];
  2425. char names[MAXVARS][10];
  2426. int i, maxnl, args;
  2427. /* copy name to filename and remove trailing spaces if any */
  2428. copy_string(filename, name, 100);
  2429. /*
  2430. * Check for uninitialized arguments
  2431. */
  2432. if (*numtimes < 1) {
  2433. printf("Error: numtimes invalid\n");
  2434. return 0;
  2435. }
  2436. if (*numvars < 1) {
  2437. printf("Error: numvars invalid\n");
  2438. return 0;
  2439. }
  2440. if (*nr < 2) {
  2441. printf("Error: nr invalid\n");
  2442. return 0;
  2443. }
  2444. if (*nc < 2) {
  2445. printf("Error: nc invalid\n");
  2446. return 0;
  2447. }
  2448. maxnl = 0;
  2449. for (i = 0; i < *numvars; i++) {
  2450. if (nl[i] < 1) {
  2451. printf("Error: nl(%d) invalid\n", i + 1);
  2452. return 0;
  2453. }
  2454. if (nl[i] > maxnl) {
  2455. maxnl = nl[i];
  2456. }
  2457. }
  2458. for (i = 0; i < *numvars; i++) {
  2459. if (copy_string2(names[i], varname[i], 10) == 0) {
  2460. printf("Error: uninitialized varname(%d)\n", i + 1);
  2461. return 0;
  2462. }
  2463. }
  2464. for (i = 0; i < *numtimes; i++) {
  2465. if (timestamp[i] < 0) {
  2466. printf("Error: times(%d) invalid\n", i + 1);
  2467. return 0;
  2468. }
  2469. if (datestamp[i] < 0) {
  2470. printf("Error: dates(%d) invalid\n", i + 1);
  2471. return 0;
  2472. }
  2473. }
  2474. if (*compressmode != 1 && *compressmode != 2 && *compressmode != 4) {
  2475. printf("Error: compressmode invalid\n");
  2476. return 0;
  2477. }
  2478. switch (*projection) {
  2479. case 0:
  2480. args = 4;
  2481. break;
  2482. case 1:
  2483. args = 0;
  2484. if (IS_MISSING(proj_args[0])) {
  2485. printf("Error: northlat (proj_args(1)) invalid\n");
  2486. return 0;
  2487. }
  2488. if (IS_MISSING(proj_args[1])) {
  2489. printf("Error: westlon (proj_args(2)) invalid\n");
  2490. return 0;
  2491. }
  2492. if (IS_MISSING(proj_args[2])) {
  2493. printf("Error: latinc (proj_args(3)) invalid\n");
  2494. return 0;
  2495. }
  2496. if (IS_MISSING(proj_args[3])) {
  2497. printf("Error: loninc (proj_args(4)) invalid\n");
  2498. return 0;
  2499. }
  2500. break;
  2501. case 2:
  2502. args = 6;
  2503. break;
  2504. case 3:
  2505. args = 5;
  2506. break;
  2507. case 4:
  2508. args = 7;
  2509. break;
  2510. default:
  2511. args = 0;
  2512. printf("Error: projection invalid\n");
  2513. return 0;
  2514. }
  2515. for (i = 0; i < args; i++) {
  2516. if (IS_MISSING(proj_args[i])) {
  2517. printf("Error: proj_args(%d) invalid\n", i + 1);
  2518. return 0;
  2519. }
  2520. }
  2521. switch (*vertical) {
  2522. case 0:
  2523. /* WLH 31 Oct 96 - just fall through
  2524. args = 4;
  2525. break;
  2526. */
  2527. case 1:
  2528. args = 0;
  2529. if (IS_MISSING(vert_args[0])) {
  2530. printf("Error: bottomhgt (vert_args(1)) invalid\n");
  2531. return 0;
  2532. }
  2533. if (IS_MISSING(vert_args[1])) {
  2534. printf("Error: hgtinc (vert_args(2)) invalid\n");
  2535. return 0;
  2536. }
  2537. break;
  2538. case 2:
  2539. case 3:
  2540. args = maxnl;
  2541. break;
  2542. default:
  2543. args = 0;
  2544. printf("Error: vertical invalid\n");
  2545. return 0;
  2546. }
  2547. for (i = 0; i < args; i++) {
  2548. if (IS_MISSING(vert_args[i])) {
  2549. printf("Error: vert_args(%d) invalid\n", i + 1);
  2550. return 0;
  2551. }
  2552. }
  2553. return v5dCreate(filename, *numtimes, *numvars, *nr, *nc, nl,
  2554. (const char (*)[10])names, timestamp, datestamp,
  2555. *compressmode,
  2556. *projection, proj_args, *vertical, vert_args);
  2557. }
  2558. /*
  2559. * Create a simple v5d file. See README file for argument descriptions.
  2560. * Return: 1 = ok, 0 = error.
  2561. */
  2562. #ifdef UNDERSCORE
  2563. int v5dcreatesimple_
  2564. #else
  2565. # ifdef _CRAY
  2566. int V5DCREATESIMPLE
  2567. # else
  2568. int v5dcreatesimple
  2569. # endif
  2570. #endif
  2571. (const char *name, const int *numtimes, const int *numvars,
  2572. const int *nr, const int *nc, const int *nl,
  2573. const char varname[][10],
  2574. const int timestamp[], const int datestamp[],
  2575. const float *northlat, const float *latinc,
  2576. const float *westlon, const float *loninc,
  2577. const float *bottomhgt, const float *hgtinc)
  2578. {
  2579. int compressmode, projection, vertical;
  2580. float projarg[100], vertarg[MAXLEVELS];
  2581. int varnl[MAXVARS];
  2582. int i;
  2583. for (i = 0; i < MAXVARS; i++) {
  2584. varnl[i] = *nl;
  2585. }
  2586. compressmode = 1;
  2587. projection = 1;
  2588. projarg[0] = *northlat;
  2589. projarg[1] = *westlon;
  2590. projarg[2] = *latinc;
  2591. projarg[3] = *loninc;
  2592. vertical = 1;
  2593. vertarg[0] = *bottomhgt;
  2594. vertarg[1] = *hgtinc;
  2595. #ifdef UNDERSCORE
  2596. return v5dcreate_
  2597. #else
  2598. # ifdef _CRAY
  2599. return V5DCREATE
  2600. # else
  2601. return v5dcreate
  2602. # endif
  2603. #endif
  2604. (name, numtimes, numvars, nr, nc, varnl,
  2605. varname, timestamp, datestamp, &compressmode,
  2606. &projection, projarg, &vertical, vertarg);
  2607. }
  2608. /*
  2609. * Set lowest levels for each variable (other than default of 0).
  2610. * Input: lowlev - array [NumVars] of ints
  2611. * Return: 1 = ok, 0 = error
  2612. */
  2613. #ifdef UNDERSCORE
  2614. int v5dsetlowlev_
  2615. #else
  2616. # ifdef _CRAY
  2617. int V5DSETLOWLEV
  2618. # else
  2619. int v5dsetlowlev
  2620. # endif
  2621. #endif
  2622. (int *lowlev)
  2623. {
  2624. return v5dSetLowLev(lowlev);
  2625. }
  2626. /*
  2627. * Set the units for a variable.
  2628. * Input: var - variable number in [1,NumVars]
  2629. * units - a character string
  2630. * Return: 1 = ok, 0 = error
  2631. */
  2632. #ifdef UNDERSCORE
  2633. int v5dsetunits_
  2634. #else
  2635. # ifdef _CRAY
  2636. int V5DSETUNITS
  2637. # else
  2638. int v5dsetunits
  2639. # endif
  2640. #endif
  2641. (int *var, char *name)
  2642. {
  2643. return v5dSetUnits(*var, name);
  2644. }
  2645. /*
  2646. * Write a grid of data to the file.
  2647. * Input: time - timestep in [1,NumTimes]
  2648. * var - timestep in [1,NumVars]
  2649. * data - array [nr*nc*nl] of floats
  2650. * Return: 1 = ok, 0 = error
  2651. */
  2652. #ifdef UNDERSCORE
  2653. int v5dwrite_
  2654. #else
  2655. # ifdef _CRAY
  2656. int V5DWRITE
  2657. # else
  2658. int v5dwrite
  2659. # endif
  2660. #endif
  2661. (const int *time, const int *var, const float *data)
  2662. {
  2663. return v5dWrite(*time, *var, data);
  2664. }
  2665. /*
  2666. * Specify the McIDAS GR3D file number and grid number which correspond
  2667. * to the grid specified by time and var.
  2668. * Input: time, var - timestep and variable of grid (starting at 1)
  2669. * mcfile, mcgrid - McIDAS grid file number and grid number
  2670. * Return: 1 = ok, 0 = errror (bad time or var)
  2671. */
  2672. #ifdef UNDERSCORE
  2673. int v5dmcfile_
  2674. #else
  2675. # ifdef _CRAY
  2676. int V5DMCFILE
  2677. # else
  2678. int v5dmcfile
  2679. # endif
  2680. #endif
  2681. (const int *time, const int *var, const int *mcfile, const int *mcgrid)
  2682. {
  2683. if (*time < 1 || *time > Simple->NumTimes) {
  2684. printf("Bad time argument to v5dSetMcIDASgrid: %d\n", *time);
  2685. return 0;
  2686. }
  2687. if (*var < 1 || *var > Simple->NumVars) {
  2688. printf("Bad var argument to v5dSetMcIDASgrid: %d\n", *var);
  2689. return 0;
  2690. }
  2691. Simple->McFile[*time - 1][*var - 1] = (short)*mcfile;
  2692. Simple->McGrid[*time - 1][*var - 1] = (short)*mcgrid;
  2693. return 1;
  2694. }
  2695. /*
  2696. * Close a simple v5d file.
  2697. */
  2698. #ifdef UNDERSCORE
  2699. int v5dclose_(void)
  2700. #else
  2701. # ifdef _CRAY
  2702. int V5DCLOSE(void)
  2703. # else
  2704. int v5dclose(void)
  2705. # endif
  2706. #endif
  2707. {
  2708. return v5dClose();
  2709. }