burn7.cpp 171 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337
  1. /* c++ -O2 -o burn7.x burn7.cpp -lm -lnetcdf_c++ -lnetcdf */
  2. #define NETCDF_OUTPUT
  3. #define V0 "burn 7.7 (02-Feb-2017)"
  4. #define V1 "KlimaCampus"
  5. #define V2 "Usage: burn7 [-help|-c|-d|-m|-n|-r|-s] <modelfile> <resultfile>"
  6. #define V3 "New: option <-g> writes Grads ctl for service plotting"
  7. #define V4 "New: comments (#) are allowed in namelist file"
  8. /* ============= */
  9. /* include files */
  10. /* ============= */
  11. #include <ctype.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <math.h>
  16. #include <time.h>
  17. #include <sys/resource.h>
  18. #include <vector>
  19. #include <valarray>
  20. #ifdef OPEN_MP
  21. #include <omp.h>
  22. #endif
  23. #ifdef NETCDF_OUTPUT
  24. #include <netcdfcpp.h>
  25. #endif
  26. using namespace std;
  27. #define LONG long long
  28. #ifndef M_PI
  29. #define M_PI 3.1415926535
  30. #endif
  31. #ifndef M_SQRT2
  32. #define M_SQRT2 1.4142136
  33. #endif
  34. #ifndef MAX
  35. #define MAX(v1,v2) ((v1) > (v2) ? (v1) : (v2))
  36. #endif
  37. #ifndef min
  38. #define min(v1,v2) ((v1) < (v2) ? (v1) : (v2))
  39. #endif
  40. #ifndef abs
  41. #define abs(x) ((x) >= 0 ? (x) : -(x))
  42. #endif
  43. #ifndef TRUE
  44. #define TRUE 1
  45. #endif
  46. #ifndef FALSE
  47. #define FALSE 0
  48. #endif
  49. #define LEV_SURFACE 1
  50. #define LEV_99 99
  51. #define LEV_ISOBARIC 100
  52. #define LEV_MEANSEA 102
  53. #define LEV_ALTITUDE 103
  54. #define LEV_HEIGHT 105
  55. #define LEV_SIGMA 107
  56. #define LEV_HYBRID 109
  57. #define LEV_GROUND 112
  58. #define REP_REGULAR 0
  59. #define REP_GAUSS 4
  60. #define REP_SPECTRAL 50
  61. #define MAX_HOURS 4
  62. #define MAX_LEVELS 99
  63. #define MAX_NVCT (MAX_LEVELS * 2 + 2)
  64. #define L_TIMES_RHOH2O (-333700000.0)
  65. #define EARTH_RADIUS 6371220.0
  66. #define MARS_RADIUS 3400000.0
  67. #define SQUARE_RADIUS (-PlanetRadius * PlanetRadius)
  68. #define EARTH_GRAV 9.80665
  69. #define MARS_GRAV 3.728
  70. #define RG (1.0 / Grav)
  71. #define MARS_RD (189.0 )
  72. /* ************************************** */
  73. /* Thermodynamical constants adopted from */
  74. /* ECMWF IFS-Code */
  75. /* ************************************** */
  76. #define RKBOL (1.380658e-23)
  77. #define RNAVO (6.0221367e+23)
  78. #define R (RKBOL * RNAVO)
  79. #define RMD (28.9644)
  80. #define RMV (18.0153)
  81. #define EARTH_RD (1000. * R / RMD)
  82. #define RV (1000. * R / RMV)
  83. #define RCPD (3.5 * RD)
  84. #define RCPV (4.0 * RV)
  85. #define RETV (RV / RD - 1.)
  86. #define RCW (4218.)
  87. #define RCS (2106.)
  88. #define RTT (273.16)
  89. #define RLVTT (2.5008e+6)
  90. #define RLSTT (2.8345e+6)
  91. #define RESTT (611.14)
  92. #define RLAPSE (0.0065)
  93. #ifdef NETCDF_OUTPUT
  94. NcFile *NetFile;
  95. NcVar *LonVar;
  96. NcVar *LatVar;
  97. NcVar *LevVar;
  98. NcVar *TimVar;
  99. NcDim *LonDim;
  100. NcDim *LatDim;
  101. NcDim *LevDim;
  102. NcDim *TimDim;
  103. #endif
  104. int SaveMemory = 0; /* Switch on for dynamic memory usage */
  105. int PolyCreate = 0; /* Create polynomials files for hires T1365 and more */
  106. int PolyDisk = 0; /* Read polynomials from disk */
  107. int GaussGrid = -1; /* 1: use Gaussian grid, 0: use regular grid */
  108. int DPM = 0; /* Days Per Month */
  109. int DPY = 0; /* Days Per Year */
  110. int DayDivisor = 0; /* Use for day adjustment if more than 99 days per month */
  111. char VerType; /* s=Sigma p=Pressure */
  112. char HorType; /* s=Spherical f=Fourier z=Zonal Mean g=Gauss Grid */
  113. char *filename;
  114. char ifile[256]; // name of input file (PUMA-II format)
  115. char ofile[256]; // Name of output file (Service or NetCDF format)
  116. char gfile[256]; // Name of Grads control file
  117. char rfile[256]; // Name of Grads data file (for zonal means only)
  118. #define MAX_NL 40960
  119. char namelist[MAX_NL];
  120. char AllocName[256];
  121. int PumaCode;
  122. int PumaLevel;
  123. int RepGrib;
  124. int Debug;
  125. int Dim3FC ;
  126. int Dim3SP ;
  127. int Dim3GG ;
  128. int Dim3GP ;
  129. int DimFC ; // Dimension of fourier array
  130. int DimGP ; // Dimension of output grid
  131. int DimGG ; // Dimension of Gauss grid
  132. int DimAB ; // Dimension of array buffer
  133. int DimSP ;
  134. int DimSP_half ;
  135. int CoreBigEndian ; // Do we run on a big endian machine ?
  136. int FileBigEndian ;
  137. int Endian = 0 ; /* Marker for reverse endian format */
  138. int LongFCW = 0 ; /* Flag for 64bit (1) or 32bit (0) FCW's */
  139. int RealSize = 4 ; /* Size of real data (4 = float) (8 = double) */
  140. int HeadSize = 32 ; // 32:Service single 64:Service double
  141. int EndOfMonth ;
  142. int EndOfTerm ;
  143. int Fouriers ;
  144. int HumInfo ; // Flag for humidity info issued
  145. double Grav = EARTH_GRAV;
  146. double SigmaTop = 0.0;
  147. int NetCDF ;
  148. int GaussianOutput = 1;
  149. int Grads ;
  150. int HeaderWords ; /* Length of file header in 32-bit words */
  151. int Gats ;
  152. int Lats ;
  153. int AllLevs = 0 ; // # of sigma levels in data file
  154. int SigLevs = 0 ; // # of sigma levels used
  155. int SingleLevel = 0 ; // Set to true for SAM/SOM models
  156. double LevelFactor = 1.0 ; // Multiplier for head(2)
  157. int LevelType ;
  158. int Gons ;
  159. int Lons ;
  160. int Cyclical = 0 ; // 1 = Cyclical completion (Lons from 0 to 360)
  161. double L_times_rhoH2O = L_TIMES_RHOH2O;
  162. int mars ;
  163. int Mean ;
  164. int MeanCount ; // Count terms during month
  165. int Multi ;
  166. int FirstMonth = 1;
  167. int LastMonth = 12;
  168. double PlanetRadius= EARTH_RADIUS;
  169. double RD = EARTH_RD;
  170. int Spectral = FALSE;
  171. int TermCount ;
  172. int MonthCount ;
  173. int OutputCount ;
  174. int Truncation = 0;
  175. int Waves ;
  176. int SpecialUV ;
  177. struct tm NewDate;
  178. struct tm OldDate;
  179. int NewMonth;
  180. int OldMonth;
  181. // Some functions for a nice printout
  182. #define COLS 72
  183. void Stars(int n) {while (n--) putchar('*');}
  184. void ErrStars(int n) {while (n--) putc('*',stderr);}
  185. void Blanks(int n) {while (n--) putchar(' ');}
  186. void Dashes(int n) {while (n--) putchar('-');}
  187. void NewLine(void) {putchar('\n');}
  188. void ErrNewLine(void) {putc('\n',stderr);}
  189. void StarLine(void) {Stars(COLS); NewLine();}
  190. /* ==================================== */
  191. /* Abort - Print error message and exit */
  192. /* ==================================== */
  193. void Abort(const char *errtext)
  194. {
  195. Stars(min(80,strlen(errtext))); NewLine();
  196. puts(errtext); NewLine();
  197. Stars(min(80,strlen(errtext))); NewLine();
  198. ErrStars(min(80,strlen(errtext))); ErrNewLine();
  199. fputs(errtext,stderr); ErrNewLine();
  200. ErrStars(min(80,strlen(errtext))); ErrNewLine();
  201. exit(1);
  202. }
  203. void BlankLine(void)
  204. {
  205. putchar('*');
  206. Blanks(COLS-2);
  207. putchar('*');
  208. NewLine();
  209. }
  210. void DashLine(void)
  211. {
  212. putchar('*');
  213. putchar(' ');
  214. Dashes(COLS-4);
  215. putchar(' ');
  216. putchar('*');
  217. NewLine();
  218. }
  219. void CenterText(const char *t)
  220. {
  221. int i,j,l;
  222. l = strlen(t);
  223. if (l < 1) return;
  224. if (l > COLS-4) puts(t);
  225. else
  226. {
  227. i = (COLS - 4 - l) / 2;
  228. j = (COLS - 4 - l - i);
  229. putchar('*');
  230. Blanks(i+1);
  231. fputs(t,stdout);
  232. Blanks(j+1);
  233. putchar('*');
  234. NewLine();
  235. }
  236. }
  237. void LeftText(const char *t)
  238. {
  239. int l;
  240. l = strlen(t);
  241. if (l < 1) return;
  242. if (l > COLS-4) puts(t);
  243. else
  244. {
  245. putchar('*');
  246. putchar(' ');
  247. fputs(t,stdout);
  248. Blanks(COLS - l - 3);
  249. putchar('*');
  250. NewLine();
  251. }
  252. }
  253. #define MAX_ID_LEN 8
  254. #define MAX_NA_LEN 32
  255. #define MAX_UN_LEN 16
  256. class Control
  257. {
  258. public:
  259. int readit ;
  260. int needed ;
  261. int selected ;
  262. int detected ;
  263. int hlev ;
  264. int plev ;
  265. int loff ;
  266. int twod ;
  267. int code ;
  268. valarray<double>hsp;
  269. valarray<double>hfc;
  270. valarray<double>hgp;
  271. valarray<double>pgp;
  272. valarray<double>mgp;
  273. valarray<double>pfc;
  274. valarray<double>psp;
  275. char Id[MAX_ID_LEN];
  276. char Na[MAX_NA_LEN];
  277. char Un[MAX_UN_LEN];
  278. #ifdef NETCDF_OUTPUT
  279. NcVar *NetVar ;
  280. #endif
  281. void Status(void);
  282. void Init(const char* Idf, const char *Name, const char *Units, int TwoD);
  283. void SetHSpec(int Hlev, int Plev, int Twod);
  284. void SetHFour(int Hlev, int Plev, int Twod);
  285. void SetHGrid(int Hlev, int Plev, int Twod);
  286. void SetPGrid(void);
  287. void SetPFour(void);
  288. void SetPSpec(void);
  289. };
  290. void Control::Status(void)
  291. {
  292. printf("\nStatus for code %3d: %s\n",code,Id);
  293. printf("-------------------------\n");
  294. printf("needed: %5d\n",needed);
  295. printf("selected: %5d\n",selected);
  296. printf("detected: %5d\n",detected);
  297. printf("hlev: %5d\n",hlev);
  298. printf("plev: %5d\n",plev);
  299. printf("twod: %5d\n",twod);
  300. printf("hsp: %5ld\n",hsp.size());
  301. printf("hfc: %5ld\n",hfc.size());
  302. printf("hgp: %5ld\n",hgp.size());
  303. printf("pgp: %5ld\n",pgp.size());
  304. printf("mean: %5ld\n",mgp.size());
  305. printf("pfc: %5ld\n",pfc.size());
  306. printf("psp: %5ld\n",psp.size());
  307. if (hgp.size()) printf("mean of hgp: %16.10lf\n",hgp.sum() / hgp.size());
  308. if (pgp.size()) printf("mean of pgp: %16.10lf\n",pgp.sum() / pgp.size());
  309. };
  310. void Control::Init(const char* Idf, const char *Name, const char *Units, int TwoD)
  311. {
  312. strncpy(Id,Idf ,MAX_ID_LEN-1);
  313. strncpy(Na,Name ,MAX_NA_LEN-1);
  314. strncpy(Un,Units,MAX_UN_LEN-1);
  315. twod = TwoD;
  316. }
  317. void Control::SetHSpec(int Hlev, int Plev, int Twod)
  318. {
  319. int OldSize;
  320. int NewSize;
  321. hlev = Hlev;
  322. plev = Plev;
  323. twod = Twod;
  324. OldSize = hsp.size();
  325. NewSize = Hlev * DimSP;
  326. if (NewSize == OldSize) return;
  327. hsp.resize(NewSize);
  328. if (Debug)
  329. {
  330. char tb[COLS];
  331. if (OldSize == 0)
  332. sprintf(tb,"Alloc: %p %6s[%3d].hsp %6ld double",&hsp[0],Id,code,hsp.size());
  333. else
  334. sprintf(tb,"Realloc: %p %6s[%3d].hsp %6ld double",&hsp[0],Id,code,hsp.size());
  335. LeftText(tb);
  336. }
  337. }
  338. void Control::SetHFour(int Hlev, int Plev, int Twod)
  339. {
  340. if (hfc.size() == Hlev * DimFC) return;
  341. hlev = Hlev;
  342. plev = Plev;
  343. twod = Twod;
  344. hfc.resize(hlev * DimFC);
  345. if (Debug)
  346. {
  347. char tb[COLS];
  348. sprintf(tb,"Alloc: %p %6s[%3d].hfc %6ld double",&hfc[0],Id,code,hfc.size());
  349. LeftText(tb);
  350. }
  351. }
  352. void Control::SetPFour(void)
  353. {
  354. if (pfc.size() == plev * DimFC) return;
  355. pfc.resize(plev * DimFC);
  356. if (Debug)
  357. {
  358. char tb[COLS];
  359. sprintf(tb,"Alloc: %p %6s[%3d].pfc %6ld double",&pfc[0],Id,code,pfc.size());
  360. LeftText(tb);
  361. }
  362. }
  363. void Control::SetHGrid(int Hlev, int Plev, int Twod)
  364. {
  365. if (hgp.size() == Hlev * DimGP) return;
  366. hlev = Hlev;
  367. plev = Plev;
  368. twod = Twod;
  369. hgp.resize(hlev * DimGP);
  370. if (Debug)
  371. {
  372. char tb[COLS];
  373. sprintf(tb,"Alloc: %p %6s[%3d].hgp %6d double",&hgp[0],Id,code,hlev*DimGP);
  374. LeftText(tb);
  375. }
  376. }
  377. void Control::SetPGrid(void)
  378. {
  379. if (twod && hgp.size())
  380. {
  381. pgp.resize(DimGP);
  382. pgp = hgp;
  383. hgp.resize(0);
  384. if (Debug)
  385. {
  386. char tb[COLS];
  387. sprintf(tb,"Moved: %p %6s[%3d].hgp to pgp",&pgp[0],Id,code);
  388. LeftText(tb);
  389. }
  390. }
  391. else if (pgp.size() != plev * DimGP)
  392. {
  393. pgp.resize(plev * DimGP);
  394. if (Debug)
  395. {
  396. char tb[COLS];
  397. sprintf(tb,"Alloc: %p %6s[%3d].pgp %6d double",&pgp[0],Id,code,plev*DimGP);
  398. LeftText(tb);
  399. }
  400. }
  401. }
  402. void Control::SetPSpec(void)
  403. {
  404. int OldSize;
  405. int NewSize;
  406. OldSize = psp.size();
  407. NewSize = plev * DimSP;
  408. if (NewSize == OldSize) return;
  409. psp.resize(NewSize);
  410. if (Debug)
  411. {
  412. char tb[COLS];
  413. if (OldSize == 0)
  414. sprintf(tb,"Alloc: %p %6s[%3d].psp %6ld double",&psp[0],Id,code,psp.size());
  415. else
  416. sprintf(tb,"Realloc: %p %6s[%3d].psp %6ld double",&psp[0],Id,code,psp.size());
  417. LeftText(tb);
  418. }
  419. }
  420. #define CODES 512
  421. #define MAXCODES (CODES+5)
  422. #define GEOSCODE 129
  423. #define TCODE 130
  424. #define UCODE 131
  425. #define VCODE 132
  426. #define SHCODE 133
  427. #define PSCODE 134
  428. #define WCODE 135
  429. #define WZCODE 137
  430. #define VORCODE 138
  431. #define STRCODE 148
  432. #define VELCODE 149
  433. #define SLPCODE 151
  434. #define LNPSCODE 152
  435. #define DIVCODE 155
  436. #define ZCODE 156
  437. #define RHCODE 157
  438. int SpecialCodes[4] = {DIVCODE,VORCODE,STRCODE,VELCODE};
  439. Control All[MAXCODES];
  440. Control *Geopotential = &All[129];
  441. Control *Temperature = &All[130];
  442. Control *u_wind = &All[131];
  443. Control *v_wind = &All[132];
  444. Control *Humidity = &All[133];
  445. Control *Ps = &All[134];
  446. Control *Omega = &All[135];
  447. Control *w_wind = &All[137];
  448. Control *Vorticity = &All[138];
  449. Control *Ts = &All[139];
  450. Control *StreamF = &All[148];
  451. Control *VeloPot = &All[149];
  452. Control *SLP = &All[151];
  453. Control *LnPs = &All[152];
  454. Control *Divergence = &All[155];
  455. Control *GeopotHeight = &All[156];
  456. Control *Rhumidity = &All[157];
  457. Control *speed = &All[259];
  458. Control *precip = &All[260];
  459. Control *net_top = &All[261];
  460. Control *net_bot = &All[262];
  461. Control *net_heat = &All[263];
  462. Control *net_water = &All[264];
  463. Control *sw_atm = &All[268];
  464. Control *lw_atm = &All[269];
  465. Control *net_atm = &All[270];
  466. Control *surf_runoff = &All[271];
  467. Control *dpsdx = &All[273];
  468. Control *dpsdy = &All[274];
  469. Control *fresh_water = &All[275];
  470. Control *HalfPress = &All[277];
  471. Control *FullPress = &All[278];
  472. Control *ThetaH = &All[279];
  473. Control *ThetaF = &All[280];
  474. int *vert_index;
  475. valarray<double>Orography;
  476. double *poli;
  477. double *pol2;
  478. double *pliu;
  479. double *pliv;
  480. char polin[80]; /* filenames for polynomial files */
  481. char pol2n[80];
  482. char pliun[80];
  483. char plivn[80];
  484. FILE *polif;
  485. FILE *pol2f;
  486. FILE *pliuf;
  487. FILE *plivf;
  488. int OutLevs; /* number of requested output levels */
  489. int nrpl; /* number of requested pressure levels */
  490. int nrml; /* number of requested model levels */
  491. int nrqh;
  492. #define ATTR_MAX 20
  493. int nattr; /* number of global attributes (NetCDF) */
  494. char AttrNam[ATTR_MAX][80];
  495. char AttrVal[ATTR_MAX][80];
  496. int nvct = 0;
  497. double vct[MAX_NVCT];
  498. int DaysPerYear = 360;
  499. double DataStep = 0.0;
  500. int DeltaDy;
  501. int DeltaHr;
  502. int DeltaMn;
  503. vector<int>HeadSt(8,0); // First header vector
  504. vector<int>HeadIn(8,0); // Input header vector
  505. vector<int>HeadOu(8,0); // Output header vector
  506. #define HYB_SPEC 0
  507. #define HYB_FOUR 1
  508. #define HYB_ZONM 2
  509. #define HYB_GRID 3
  510. #define PRE_GRID 4
  511. #define PRE_FOUR 5
  512. #define PRE_ZONM 6
  513. #define PRE_SPEC 7
  514. int OutRep = HYB_SPEC; // Output Representation
  515. int hours[MAX_HOURS+1];
  516. double level[MAX_LEVELS+1];
  517. int LevelFound[MAX_LEVELS+1];
  518. double hPa[MAX_LEVELS];
  519. int mol[MAX_LEVELS];
  520. int mom[MAX_LEVELS]; /* Mask for selected levels */
  521. int LevelUnits[MAX_LEVELS];
  522. int SigmaF[MAX_LEVELS];
  523. double *Record_double;
  524. float *Record_float; // Buffer for FORTRAN records
  525. int *Record_int; // All share the same space
  526. unsigned short *Record_short;
  527. char *Record_char;
  528. double *CosPhi; /* Cosine of Phi (Latitude) */
  529. double *RevCosPhi; /* 1.0 / CosPhi */
  530. double *DerivationFactor;
  531. double *wfc; /* FFT work array */
  532. double *wgp; /* FFT work array */
  533. int ifax[10]; /* FFT factorization */
  534. FILE *fpi;
  535. FILE *gp;
  536. class RegLon // class for equidistant longituinal array
  537. {
  538. char Name[16]; // Array name
  539. double DeltaLam; // Distance of Longitudes
  540. public:
  541. int Lons; // Number of latitudes
  542. double *Lam; // Coordinate in degrees
  543. RegLon(int, const char *); // Constructor
  544. ~RegLon(void); // Destructor
  545. void PrintArray(void); // Print table
  546. };
  547. RegLon::RegLon(int n, const char *name)
  548. {
  549. int jlon;
  550. Lons = n;
  551. DeltaLam = 360.0 / Lons;
  552. Lam = new double[Lons+1];
  553. for (jlon=0 ; jlon < Lons ; ++jlon)
  554. {
  555. Lam[jlon] = jlon * DeltaLam;
  556. }
  557. Lam[Lons] = 360.0;
  558. strncpy(Name,name,15);
  559. }
  560. RegLon::~RegLon(void)
  561. {
  562. delete Lam;
  563. }
  564. void RegLon::PrintArray(void)
  565. {
  566. int jlon;
  567. printf("*******************************\n");
  568. printf("* %16.16s Longitude *\n",Name);
  569. printf("*******************************\n");
  570. for (jlon=0 ; jlon < Lons ; ++jlon)
  571. printf("* %16d %10.4f *\n",jlon,Lam[jlon]);
  572. printf("*******************************\n");
  573. }
  574. class RegLat // class for equidistant latitudinal array
  575. {
  576. char Name[16]; // Array name
  577. double DeltaPhi; // Distance of latitudes
  578. double FirstPhi; // First latitude
  579. public:
  580. int Lats; // Number of latitudes
  581. double *Phi; // Coordinate in degrees
  582. double *gmu; // Sine of phi
  583. double *gwt; // Gaussian weight
  584. RegLat(int, const char *); // Constructor
  585. ~RegLat(void); // Destructor
  586. void PrintArray(void); // Print table
  587. };
  588. RegLat::RegLat(int n, const char *name)
  589. {
  590. int jlat;
  591. Lats = n;
  592. DeltaPhi = 180.0 / (Lats - 1);
  593. Phi = new double[Lats];
  594. gmu = new double[Lats];
  595. gwt = new double[Lats];
  596. if (Lats & 1) /* odd -> start with DeltaPhi */
  597. {
  598. DeltaPhi = 180.0 / (Lats + 1);
  599. FirstPhi = 90.0 - DeltaPhi;
  600. }
  601. else /* even -> start with 0.5 DeltaPhi */
  602. {
  603. DeltaPhi = 180.0 / Lats;
  604. FirstPhi = 90.0 - 0.5 * DeltaPhi;
  605. }
  606. for (jlat=0 ; jlat < Lats ; ++jlat)
  607. {
  608. Phi[jlat] = FirstPhi - jlat * DeltaPhi;
  609. gmu[jlat] = sin(Phi[jlat] * M_PI / 180.0);
  610. gwt[jlat] = 0.0;
  611. }
  612. strncpy(Name,name,15);
  613. }
  614. RegLat::~RegLat(void)
  615. {
  616. delete Phi;
  617. delete gmu;
  618. delete gwt;
  619. }
  620. void RegLat::PrintArray(void)
  621. {
  622. int jlat;
  623. printf("*******************************\n");
  624. printf("* %16.16s Latitude *\n",Name);
  625. printf("*******************************\n");
  626. for (jlat=0 ; jlat < Lats ; ++jlat)
  627. printf("* %16d %10.4f *\n",jlat,Phi[jlat]);
  628. printf("*******************************\n");
  629. }
  630. class GauLat : public RegLat
  631. {
  632. public:
  633. GauLat(int, const char *); // Constructor
  634. ~GauLat(void); // Destructor
  635. private:
  636. void IniGau(void);
  637. double nlp(int, double);
  638. double dlp(int, double);
  639. };
  640. GauLat::GauLat(int n, const char *name) : RegLat(n, name)
  641. {
  642. int jlat;
  643. IniGau();
  644. for (jlat = 0 ; jlat < Lats ; ++jlat)
  645. Phi[jlat] = 180.0 * asin(gmu[jlat]) / M_PI;
  646. }
  647. GauLat::~GauLat(void)
  648. {
  649. }
  650. /* ============================== */
  651. /* Calculate Legendre Polynomials */
  652. /* ============================== */
  653. double GauLat::nlp(int k, double p) // After Nodorp (1988)
  654. {
  655. int j;
  656. double z0,z1,z2,z3,z4;
  657. z0 = acos(p);
  658. z1 = 1.0;
  659. z2 = 0.0;
  660. z3 = 0.0;
  661. for (j=k ; j >= 0 ; j-=2)
  662. {
  663. z3 = z1 * cos(j * z0);
  664. z2 += z3;
  665. z4 = (k-j+1) * (k+j)/2;
  666. z1 *= z4 / (z4+j-1);
  667. }
  668. if (k % 2 == 0) z2 -= 0.5 * z3;
  669. z0 = sqrt(2.0);
  670. for (j=1; j <= k ; ++j)
  671. z0 *= sqrt(1.0 - 0.25/(j*j));
  672. return (z0*z2);
  673. }
  674. /* ============================================= */
  675. /* Calculate Derivatives of Legendre Polynomials */
  676. /* ============================================= */
  677. double GauLat::dlp(int k, double p) // After Nodorp (1988)
  678. {
  679. double z0,z3,z4;
  680. if (!k) return 0.0;
  681. z0 = 1.0 / (p*p - 1.0);
  682. z3 = sqrt((k+k+1.0)/(k+k-1.0));
  683. z4 = p * nlp(k,p) - z3 * nlp(k-1,p);
  684. return(k*z0*z4);
  685. }
  686. void GauLat::IniGau(void)
  687. {
  688. int jlat,Iter;
  689. double z0, z1, z2, z3;
  690. double eps=1.e-15;
  691. z0 = M_PI / (2 * Lats + 1);
  692. z1 = 1.0 / (8 * Lats * Lats);
  693. for (jlat=0 ; jlat < Lats/2 ; ++jlat) // North to Equator
  694. {
  695. z2 = (2 * jlat + 1.5) * z0;
  696. z2 = cos(z2 + z1 / tan(z2));
  697. Iter = 0;
  698. do
  699. {
  700. z3 = nlp(Lats,z2) / dlp(Lats,z2);
  701. z2 -= z3;
  702. } while ((z3 < -eps || z3 > eps) && ++Iter < 1000);
  703. gmu[jlat] = z2;
  704. gmu[Lats-1-jlat] = -z2;
  705. }
  706. z1 = 2.0 / (Lats * Lats);
  707. for (jlat=0 ; jlat < Lats/2 ; ++jlat) // North to Equator
  708. {
  709. z0 = nlp(Lats-1,gmu[jlat]) / sqrt(Lats - 0.5);
  710. z0 = z0 * z0;
  711. gwt[jlat] = z1 * (1.0 - gmu[jlat] * gmu[jlat]) / z0;
  712. gwt[Lats-1-jlat] = gwt[jlat];
  713. }
  714. }
  715. RegLon *Outlon;
  716. RegLat *Outlat;
  717. GauLat *Gaulat;
  718. #ifdef NETCDF_OUTPUT
  719. #define TITLE "PUMA/PLASIM DATA"
  720. #define HISTORY "Created by PumaBurner 7.4"
  721. void NetOpen(char *NetFileName)
  722. {
  723. int yy,mm,dd;
  724. int jlev;
  725. int jvar;
  726. int londim;
  727. double *Outlev;
  728. const char *title=TITLE;
  729. const char *conv="CF-1.0";
  730. const char *hist=HISTORY;
  731. char cale[80];
  732. char t_unit[80];
  733. int BaseDate[4];
  734. Outlev = new double[OutLevs];
  735. if (VerType == 's') // sigma
  736. {
  737. for (jlev = 0 ; jlev < OutLevs ; ++jlev)
  738. Outlev[jlev] = 0.5 *
  739. (vct[SigLevs+mol[jlev]]+vct[SigLevs+mol[jlev]+1]);
  740. }
  741. else // pressure levels [hPa]
  742. {
  743. for (jlev = 0 ; jlev < OutLevs ; ++jlev) Outlev[jlev] = hPa[jlev];
  744. }
  745. BaseDate[0] = yy = HeadSt[2] / 10000;
  746. BaseDate[1] = mm = HeadSt[2] / 100 % 100;
  747. BaseDate[2] = dd = HeadSt[2] % 100;
  748. BaseDate[3] = 0;
  749. if (Mean)
  750. {
  751. sprintf(t_unit,"months since %04d-%02d-%02d 00:00:00",yy,mm,dd);
  752. sprintf(cale,"360_day");
  753. }
  754. else
  755. {
  756. sprintf(t_unit,"days since %04d-%02d-%02d 00:00:00",yy,mm,dd);
  757. if (DaysPerYear != 365) sprintf(cale,"%d_day",DaysPerYear);
  758. else sprintf(cale,"proleptic_gregorian");
  759. }
  760. /* Create NetCDF file */
  761. NetFile = new NcFile(NetFileName,NcFile::Replace,NULL,0,NcFile::Offset64Bits);
  762. if (!NetFile->is_valid()) Abort("Could not open NetCDF file");
  763. /* Define dimensions */
  764. if (OutRep == HYB_ZONM || OutRep == PRE_ZONM) londim = 1;
  765. else londim = Lons + Cyclical;
  766. LonDim = NetFile->add_dim("lon" , londim);
  767. LatDim = NetFile->add_dim("lat" , Lats );
  768. LevDim = NetFile->add_dim("lev" , OutLevs );
  769. TimDim = NetFile->add_dim("time" );
  770. LonVar = NetFile->add_var("lon" , ncDouble, LonDim);
  771. LatVar = NetFile->add_var("lat" , ncDouble, LatDim);
  772. LevVar = NetFile->add_var("lev" , ncDouble, LevDim);
  773. TimVar = NetFile->add_var("time", ncDouble, TimDim);
  774. LonVar->add_att("axis" ,"X" );
  775. LonVar->add_att("long_name" ,"longitude" );
  776. LonVar->add_att("standard_name","longitude" );
  777. LonVar->add_att("units" ,"degrees_east" );
  778. LatVar->add_att("axis" ,"Y" );
  779. LatVar->add_att("long_name" ,"latitude" );
  780. LatVar->add_att("standard_name","latitude" );
  781. LatVar->add_att("units" ,"degrees_north");
  782. if (VerType == 's') // sigma level
  783. {
  784. LevVar->add_att("axis" ,"Z" );
  785. LevVar->add_att("long_name" ,"sigma at layer midpoints" );
  786. LevVar->add_att("standard_name","atmosphere_sigma_coordinate");
  787. LevVar->add_att("positive" ,"down" );
  788. LevVar->add_att("units" ,"level" );
  789. }
  790. else // pressure level
  791. {
  792. LevVar->add_att("axis" ,"Z" );
  793. LevVar->add_att("long_name" ,"pressure" );
  794. LevVar->add_att("standard_name","pressure" );
  795. LevVar->add_att("units" ,"hPa" );
  796. }
  797. TimVar->add_att("calendar" ,cale );
  798. TimVar->add_att("units" ,t_unit );
  799. TimVar->add_att("base_date", 4 ,BaseDate );
  800. NetFile->add_att("title" , title);
  801. NetFile->add_att("history" , hist );
  802. NetFile->add_att("Conventions", conv );
  803. for (jvar = 0 ; jvar < nattr ; ++jvar)
  804. {
  805. NetFile->add_att(AttrNam[jvar],AttrVal[jvar]);
  806. }
  807. LonVar->put(Outlon->Lam,londim );
  808. LatVar->put(Outlat->Phi,Lats );
  809. LevVar->put(Outlev ,OutLevs);
  810. }
  811. void NetVarDefine(void)
  812. {
  813. int jvar;
  814. for (jvar = 0 ; jvar < CODES ; ++jvar)
  815. if (All[jvar].selected)
  816. {
  817. if (All[jvar].twod)
  818. {
  819. if (RealSize == 8)
  820. All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncDouble,TimDim,LatDim,LonDim);
  821. else
  822. All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncFloat ,TimDim,LatDim,LonDim);
  823. }
  824. else
  825. {
  826. if (RealSize == 8)
  827. All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncDouble,TimDim,LevDim,LatDim,LonDim);
  828. else
  829. All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncFloat ,TimDim,LevDim,LatDim,LonDim);
  830. }
  831. All[jvar].NetVar->add_att("long_name" ,All[jvar].Na);
  832. All[jvar].NetVar->add_att("standard_name",All[jvar].Na);
  833. All[jvar].NetVar->add_att("units" ,All[jvar].Un);
  834. All[jvar].NetVar->add_att("code" , jvar );
  835. if (GaussianOutput)
  836. All[jvar].NetVar->add_att("grid_type" ,"gaussian" );
  837. }
  838. }
  839. void NetBuffer(double *d, float *f)
  840. {
  841. for (int jdim = 0 ; jdim < DimGP ; ++jdim) *f++ = *d++;
  842. }
  843. void NetScale(float *f, int dim, double s)
  844. {
  845. int j;
  846. for (j = 0 ; j < dim ; ++j) *f++ *= s;
  847. }
  848. void NetScale(double *f, int dim, double s)
  849. {
  850. int j;
  851. for (j = 0 ; j < dim ; ++j) *f++ *= s;
  852. }
  853. void NetWrite32(int code, double *Var)
  854. {
  855. int jlev;
  856. if (All[code].twod)
  857. {
  858. NetBuffer(Var,Record_float);
  859. if (code==SLPCODE || code==PSCODE)
  860. NetScale(Record_float,Lats*(Lons+Cyclical),0.01);
  861. All[code].NetVar->set_cur(OutputCount);
  862. All[code].NetVar->put(Record_float,1,Lats,Lons+Cyclical);
  863. }
  864. else
  865. {
  866. for (jlev = 0 ; jlev < OutLevs ; ++jlev, Var += DimGP)
  867. {
  868. NetBuffer(Var,Record_float);
  869. if (code==WCODE)
  870. NetScale(Record_float,Lats*(Lons+Cyclical),0.01);
  871. All[code].NetVar->set_cur(OutputCount,jlev);
  872. All[code].NetVar->put(Record_float,1,1,Lats,Lons+Cyclical);
  873. }
  874. }
  875. }
  876. void NetWrite64(int code, double *Var)
  877. {
  878. int jlev;
  879. if (All[code].twod)
  880. {
  881. memcpy(Record_double,Var,DimGP * sizeof(double));
  882. if (code==SLPCODE || code==PSCODE)
  883. NetScale(Record_double,Lats*(Lons+Cyclical),0.01);
  884. All[code].NetVar->set_cur(OutputCount);
  885. All[code].NetVar->put(Record_double,1,Lats,Lons+Cyclical);
  886. }
  887. else
  888. {
  889. for (jlev = 0 ; jlev < OutLevs ; ++jlev, Var += DimGP)
  890. {
  891. memcpy(Record_double,Var,DimGP * sizeof(double));
  892. if (code==WCODE)
  893. NetScale(Record_double,Lats*(Lons+Cyclical),0.01);
  894. All[code].NetVar->set_cur(OutputCount,jlev);
  895. All[code].NetVar->put(Record_double,1,1,Lats,Lons+Cyclical);
  896. }
  897. }
  898. }
  899. void NetWriteSection(int code, double *Var)
  900. {
  901. int jvar,jlev;
  902. double *vp;
  903. for (jlev = 0 ; jlev < OutLevs ; ++jlev)
  904. {
  905. vp = Var + jlev * DimFC;
  906. if (code==SLPCODE || code==PSCODE || code==WCODE)
  907. {
  908. for (jvar = 0 ; jvar < Lats ; ++jvar)
  909. {
  910. Record_float[jvar] = vp[jvar] * 0.01;
  911. }
  912. }
  913. else
  914. {
  915. for (jvar = 0 ; jvar < Lats ; ++jvar)
  916. {
  917. Record_float[jvar] = vp[jvar];
  918. }
  919. }
  920. All[code].NetVar->set_cur(OutputCount,jlev);
  921. All[code].NetVar->put(Record_float,1,1,Lats,1);
  922. }
  923. }
  924. void NetClose(void)
  925. {
  926. int jt;
  927. double * Outtim;
  928. Outtim = new double[OutputCount];
  929. for (jt = 0 ; jt < OutputCount ; jt++) Outtim[jt] = jt;
  930. if (Mean == 0 && (DataStep < 0.99999 || DataStep > 1.00001))
  931. for (jt = 0 ; jt < OutputCount ; jt++) Outtim[jt] *= DataStep;
  932. TimVar->put(Outtim,OutputCount);
  933. delete Outtim;
  934. delete NetFile;
  935. }
  936. #endif
  937. class ServiceGrid
  938. {
  939. int HeadControl;
  940. FILE *File;
  941. float *FloatBuffer;
  942. public:
  943. int h4; // head[4] = 1st dimension
  944. int h5; // head[5] = 2nd dimension
  945. int Dim; // total dimension
  946. int FieldControl;
  947. ServiceGrid(FILE *, int, int);
  948. ~ServiceGrid(void);
  949. void Write(int *, double *);
  950. void WriteCode(int code, double *field, int twod);
  951. void Write_hspec(void);
  952. void Write_pspec(void);
  953. void Write_hfour(void);
  954. void Write_pfour(void);
  955. void Write_hgrid(void);
  956. void Write_pgrid(void);
  957. void Clear_hspec(void);
  958. void Clear_pspec(void);
  959. void Clear_hfour(void);
  960. void Clear_pfour(void);
  961. void Clear_hgrid(void);
  962. void Clear_pgrid(void);
  963. };
  964. ServiceGrid::ServiceGrid(FILE *fd, int Dim1, int Dim2)
  965. {
  966. h4 = Dim1;
  967. h5 = Dim2;
  968. Dim = Dim1 * Dim2;
  969. HeadControl = 8 * RealSize;
  970. FieldControl = Dim * RealSize;
  971. File = fd;
  972. FloatBuffer = new float[Dim];
  973. }
  974. ServiceGrid::~ServiceGrid(void)
  975. {
  976. delete FloatBuffer;
  977. }
  978. void ServiceGrid::Write(int *Head, double *Array)
  979. {
  980. int i,j;
  981. LONG lhc,lfc;
  982. if (Debug) // Check for NaN (Not A Number)
  983. {
  984. for (j=0 ; j<Dim ; ++j)
  985. {
  986. if (isnan(Array[j]))
  987. {
  988. printf("\n Head: ");
  989. for (i=0 ; i<6 ; i++) printf(" %d",Head[i]);
  990. printf("\n Array[%d] = NaN\n",j);
  991. exit(1);
  992. }
  993. }
  994. }
  995. if (RealSize == 4)
  996. {
  997. for (j=0 ; j<Dim ; ++j) FloatBuffer[j] = Array[j];
  998. if (LongFCW)
  999. {
  1000. lhc = HeadControl;
  1001. lfc = FieldControl;
  1002. fwrite(&lhc ,sizeof(lhc) ,1 ,File);
  1003. fwrite( Head ,sizeof(int) ,8 ,File);
  1004. fwrite(&lhc ,sizeof(lhc) ,1 ,File);
  1005. fwrite(&lfc ,sizeof(lfc) ,1 ,File);
  1006. fwrite( FloatBuffer,sizeof(float),Dim,File);
  1007. fwrite(&lfc ,sizeof(lfc) ,1 ,File);
  1008. }
  1009. else
  1010. {
  1011. fwrite(&HeadControl ,sizeof(int) ,1 ,File);
  1012. fwrite( Head ,sizeof(int) ,8 ,File);
  1013. fwrite(&HeadControl ,sizeof(int) ,1 ,File);
  1014. fwrite(&FieldControl,sizeof(int) ,1 ,File);
  1015. fwrite( FloatBuffer ,sizeof(float),Dim,File);
  1016. fwrite(&FieldControl,sizeof(int) ,1 ,File);
  1017. }
  1018. }
  1019. else // RealSize == 8
  1020. {
  1021. if (LongFCW)
  1022. {
  1023. lhc = HeadControl;
  1024. lfc = FieldControl;
  1025. fwrite(&lhc ,sizeof(lhc) ,1 ,File);
  1026. fwrite( Head ,sizeof(int) ,8 ,File);
  1027. fwrite(&lhc ,sizeof(lhc) ,1 ,File);
  1028. fwrite(&lfc ,sizeof(lfc) ,1 ,File);
  1029. fwrite( Array ,sizeof(double),Dim,File);
  1030. fwrite(&lfc ,sizeof(lfc) ,1 ,File);
  1031. }
  1032. else
  1033. {
  1034. long LongHead[8];
  1035. for (int i=0 ; i<8 ; ++i) LongHead[i] = Head[i];
  1036. fwrite(&HeadControl ,sizeof(int) ,1 ,File);
  1037. fwrite( LongHead ,RealSize ,8 ,File);
  1038. fwrite(&HeadControl ,sizeof(int) ,1 ,File);
  1039. fwrite(&FieldControl,sizeof(int) ,1 ,File);
  1040. fwrite( Array ,RealSize ,Dim,File);
  1041. fwrite(&FieldControl,sizeof(int) ,1 ,File);
  1042. }
  1043. }
  1044. }
  1045. void ServiceGrid::WriteCode(int code, double *field, int twod)
  1046. {
  1047. int jlev;
  1048. if (field == NULL)
  1049. {
  1050. fprintf(stderr, "*** Error in ServiceGrid::WriteCode\n");
  1051. fprintf(stderr, " Code %d not defined for this OutRep\n",code);
  1052. fprintf(stderr, " Skipping this record\n\n");
  1053. return;
  1054. }
  1055. HeadOu[0] = code;
  1056. HeadOu[4] = h4;
  1057. HeadOu[5] = h5;
  1058. if (twod)
  1059. {
  1060. HeadOu[1] = 0;
  1061. HeadOu[7] = 0;
  1062. Write(&HeadOu[0],field);
  1063. }
  1064. else for (jlev = 0; jlev < OutLevs; jlev++)
  1065. {
  1066. HeadOu[1] = LevelUnits[jlev];
  1067. HeadOu[7] = SigmaF[jlev];
  1068. Write(&HeadOu[0], field + jlev * Dim);
  1069. }
  1070. }
  1071. void ServiceGrid::Write_hspec(void)
  1072. {
  1073. for (int code = 0; code < CODES; code++)
  1074. if (All[code].selected)
  1075. WriteCode(code,&All[code].hsp[0],All[code].twod);
  1076. }
  1077. void ServiceGrid::Write_pspec(void)
  1078. {
  1079. for (int code = 0; code < CODES; code++)
  1080. if (All[code].selected)
  1081. WriteCode(code,&All[code].psp[0],All[code].twod);
  1082. }
  1083. void ServiceGrid::Clear_hspec(void)
  1084. {
  1085. for (int code = CODES-1 ; code >= 0 ; --code)
  1086. if (All[code].hsp.size() && !All[code].twod)
  1087. {
  1088. if (Debug)
  1089. {
  1090. char tb[COLS];
  1091. sprintf(tb,"Clear: %p %6s[%3d].hsp",
  1092. &All[code].hsp[0],All[code].Id,code);
  1093. LeftText(tb);
  1094. }
  1095. All[code].hsp.resize(0);
  1096. }
  1097. }
  1098. void ServiceGrid::Clear_hfour(void)
  1099. {
  1100. for (int code = CODES-1 ; code >= 0 ; --code)
  1101. if (All[code].hfc.size() && !All[code].twod)
  1102. {
  1103. if (Debug)
  1104. {
  1105. char tb[COLS];
  1106. sprintf(tb,"CLear: %p %6s[%3d].hfc",&All[code].hfc[0],All[code].Id,code);
  1107. LeftText(tb);
  1108. }
  1109. All[code].hfc.resize(0);
  1110. }
  1111. }
  1112. void ServiceGrid::Clear_hgrid(void)
  1113. {
  1114. for (int code = CODES-1 ; code >= 0 ; --code)
  1115. if (All[code].hgp.size())
  1116. {
  1117. if (Debug)
  1118. {
  1119. char tb[COLS];
  1120. sprintf(tb,"CLear: %p %6s[%3d].hgp",&All[code].hgp[0],All[code].Id,code);
  1121. LeftText(tb);
  1122. }
  1123. All[code].hgp.resize(0);
  1124. }
  1125. }
  1126. void ServiceGrid::Clear_pgrid(void)
  1127. {
  1128. for (int code = CODES-1 ; code >= 0 ; --code)
  1129. if (All[code].pgp.size())
  1130. {
  1131. if (Debug)
  1132. {
  1133. char tb[COLS];
  1134. sprintf(tb,"CLear: %p %6s[%3d].pgp",&All[code].pgp[0],All[code].Id,code);
  1135. LeftText(tb);
  1136. }
  1137. All[code].pgp.resize(0);
  1138. }
  1139. }
  1140. void ServiceGrid::Clear_pfour(void)
  1141. {
  1142. for (int code = CODES-1 ; code >= 0 ; --code)
  1143. if (All[code].pfc.size())
  1144. {
  1145. if (Debug)
  1146. {
  1147. char tb[COLS];
  1148. sprintf(tb,"CLear: %p %6s[%3d].pfc",&All[code].pfc[0],All[code].Id,code);
  1149. LeftText(tb);
  1150. }
  1151. All[code].pfc.resize(0);
  1152. }
  1153. }
  1154. void ServiceGrid::Clear_pspec(void)
  1155. {
  1156. for (int code = CODES-1 ; code >= 0 ; --code)
  1157. if (All[code].psp.size())
  1158. {
  1159. if (Debug)
  1160. {
  1161. char tb[COLS];
  1162. sprintf(tb,"CLear: %p %6s[%3d].psp",&All[code].psp[0],All[code].Id,code);
  1163. LeftText(tb);
  1164. }
  1165. All[code].psp.resize(0);
  1166. }
  1167. }
  1168. void ServiceGrid::Write_hfour(void)
  1169. {
  1170. int code;
  1171. for (code = 0; code < CODES; code++)
  1172. if (All[code].selected)
  1173. WriteCode(code,&All[code].hfc[0],All[code].twod);
  1174. }
  1175. void ServiceGrid::Write_pfour(void)
  1176. {
  1177. int code;
  1178. for (code = 0; code < CODES; code++)
  1179. if (All[code].selected)
  1180. WriteCode(code,&All[code].pfc[0],All[code].twod);
  1181. }
  1182. void ServiceGrid::Write_hgrid(void)
  1183. {
  1184. int code;
  1185. for (code = 0; code < CODES; code++)
  1186. if (All[code].selected)
  1187. {
  1188. if (All[code].hgp.size() == 0)
  1189. {
  1190. fprintf(stderr, "*** Error in ServiceGrid::Write_hgrid\n");
  1191. fprintf(stderr, " Code %d is not available on sigma level\n",code);
  1192. fprintf(stderr, " Skipping this record\n\n");
  1193. return;
  1194. }
  1195. #ifdef NETCDF_OUTPUT
  1196. if (NetCDF)
  1197. {
  1198. if (RealSize == 8) NetWrite64(code,&All[code].hgp[0]);
  1199. else NetWrite32(code,&All[code].hgp[0]);
  1200. }
  1201. else
  1202. #endif
  1203. WriteCode(code,&All[code].hgp[0],All[code].twod);
  1204. }
  1205. OutputCount++;
  1206. }
  1207. void ServiceGrid::Write_pgrid(void)
  1208. {
  1209. int code;
  1210. for (code = 0; code < CODES; code++)
  1211. if (All[code].selected)
  1212. {
  1213. #ifdef NETCDF_OUTPUT
  1214. if (NetCDF)
  1215. {
  1216. if (RealSize == 8) NetWrite64(code,&All[code].pgp[0]);
  1217. else NetWrite32(code,&All[code].pgp[0]);
  1218. }
  1219. else
  1220. #endif
  1221. WriteCode(code,&All[code].pgp[0],All[code].twod);
  1222. }
  1223. OutputCount++;
  1224. }
  1225. class ServiceSect : public ServiceGrid
  1226. {
  1227. double *Buffer;
  1228. public:
  1229. ServiceSect(FILE *, int, int);
  1230. ~ServiceSect(void);
  1231. void WriteCode(int code, double *field, int twod);
  1232. void Write_hfour(void);
  1233. void Write_pfour(void);
  1234. };
  1235. ServiceSect::ServiceSect(FILE *fd, int Dim1, int Dim2) :
  1236. ServiceGrid(fd,Dim1,Dim2)
  1237. {
  1238. Buffer = new double[Dim1*Dim2];
  1239. }
  1240. ServiceSect::~ServiceSect(void)
  1241. {
  1242. delete Buffer;
  1243. }
  1244. void ServiceSect::WriteCode(int code, double *field, int twod)
  1245. {
  1246. int jlev;
  1247. HeadOu[0] = code;
  1248. HeadOu[1] = -1;
  1249. HeadOu[7] = 0;
  1250. if (twod)
  1251. {
  1252. h5 = 1;
  1253. memcpy(Buffer,field,Lats * sizeof(double));
  1254. }
  1255. else
  1256. {
  1257. h5 = OutLevs;
  1258. for (jlev=0 ; jlev < OutLevs ; ++jlev)
  1259. memcpy(Buffer+jlev*Lats,field+jlev*DimFC,Lats*sizeof(double));
  1260. }
  1261. HeadOu[4] = h4;
  1262. HeadOu[5] = h5;
  1263. Dim = h4 * h5;
  1264. FieldControl = Dim * sizeof(float);
  1265. Write(&HeadOu[0],Buffer);
  1266. }
  1267. void ServiceSect::Write_hfour(void)
  1268. {
  1269. int code;
  1270. for (code = 0; code < CODES; code++)
  1271. if (All[code].selected)
  1272. {
  1273. #ifdef NETCDF_OUTPUT
  1274. if (NetCDF)
  1275. NetWriteSection(code,&All[code].hfc[0]);
  1276. else
  1277. #endif
  1278. WriteCode(code,&All[code].hfc[0],All[code].twod);
  1279. }
  1280. OutputCount++;
  1281. }
  1282. void ServiceSect::Write_pfour(void)
  1283. {
  1284. int code;
  1285. for (code = 0; code < CODES; code++)
  1286. if (All[code].selected)
  1287. {
  1288. #ifdef NETCDF_OUTPUT
  1289. if (NetCDF)
  1290. NetWriteSection(code,&All[code].pfc[0]);
  1291. else
  1292. #endif
  1293. WriteCode(code,&All[code].pfc[0],All[code].twod);
  1294. }
  1295. OutputCount++;
  1296. }
  1297. ServiceGrid *HybSpec;
  1298. ServiceGrid *HybFour;
  1299. ServiceGrid *HybGrid;
  1300. ServiceSect *HybSect;
  1301. void HeadToDate(vector<int>Head, struct tm *Date)
  1302. {
  1303. Date->tm_year = Head[2] / 10000;
  1304. Date->tm_mon = Head[2] / 100 % 100;
  1305. Date->tm_mday = Head[2] % 100;
  1306. Date->tm_hour = Head[3] / 100;
  1307. Date->tm_min = Head[3] % 100;
  1308. }
  1309. /* ============================================== */
  1310. /* DoubleZero - Set array of type double to zero */
  1311. /* ============================================== */
  1312. inline void DoubleZero(double *field, int words)
  1313. {
  1314. memset((char *)field,0,words * sizeof(double));
  1315. }
  1316. /* ====================== */
  1317. /* Fast Fourier Transform */
  1318. /* ====================== */
  1319. /* constants in math.h :
  1320. #define M_E 2.71828182845904523536
  1321. #define M_LOG2E 1.44269504088896340736
  1322. #define M_LOG10E 0.434294481903251827651
  1323. #define M_LN2 0.693147180559945309417
  1324. #define M_LN10 2.30258509299404568402
  1325. #define M_PI 3.14159265358979323846
  1326. #define M_PI_2 1.57079632679489661923
  1327. #define M_PI_4 0.785398163397448309616
  1328. #define M_1_PI 0.318309886183790671538
  1329. #define M_2_PI 0.636619772367581343076
  1330. #define M_1_SQRTPI 0.564189583547756286948
  1331. #define M_2_SQRTPI 1.12837916709551257390
  1332. #define M_SQRT2 1.41421356237309504880
  1333. #define M_SQRT_2 0.707106781186547524401
  1334. */
  1335. #define QUA 0.25
  1336. #define QT5 0.559016994374947
  1337. #define S36 0.587785252292473
  1338. #define S60 0.866025403784437
  1339. #define S72 0.951056516295154
  1340. #define SQ2 0.707106781186547524401
  1341. #define D60 (S60+S60)
  1342. #define FORK for(k=la;k<=kstop;k+=la){
  1343. #define LOOP for(l=0;l<la;++l){i=ibase;j=jbase;for(ijk=0;ijk<lot;++ijk){
  1344. #define ENDL i+=inc3;j+=inc4;}ibase++;jbase++;}
  1345. void fft_set(int n)
  1346. {
  1347. int j,k,nfax;
  1348. nfax = 0;
  1349. for (k = 0; k < 9; ++k) ifax[k] = 0;
  1350. ifax[9] = n;
  1351. if (n % 8 == 0) {ifax[++nfax] = 8; n /= 8;}
  1352. while (n % 6 == 0) {ifax[++nfax] = 6; n /= 6;}
  1353. while (n % 5 == 0) {ifax[++nfax] = 5; n /= 5;}
  1354. while (n % 4 == 0) {ifax[++nfax] = 4; n /= 4;}
  1355. while (n % 3 == 0) {ifax[++nfax] = 3; n /= 3;}
  1356. if (n % 2 == 0) {ifax[++nfax] = 2; n /= 2;}
  1357. ifax[0] = nfax;
  1358. for (k = 0; k < nfax/2; ++k)
  1359. {
  1360. j = ifax[k+1];
  1361. ifax[k+1] = ifax[nfax-k];
  1362. ifax[nfax-k] = j;
  1363. }
  1364. }
  1365. int rpassc(double *a, double *b, double *c, double *d,
  1366. int inc3, int inc4,
  1367. int lot , int n , int ifac, int la )
  1368. {
  1369. /*
  1370. rpassc' - performs one pass through data as part;
  1371. of multiple real fft (fourier synthesis) routine;
  1372. a is first real input vector
  1373. b is equivalent to a + la
  1374. c is first real output vector
  1375. d is equivalent to c + ifac * la
  1376. inc3 is the increment between input vectors a;
  1377. inc4 is the increment between output vectors c;
  1378. lot is the number of vectors;
  1379. n is the length of the vectors;
  1380. ifac is the current factor of n;
  1381. la is the product of previous factors;
  1382. ierr is an error indicator:;
  1383. 0 - pass completed without error;
  1384. 2 - ifac not catered for;
  1385. 3 - ifac only catered for if la=n/ifac;
  1386. */
  1387. int i0,i1,i2,i3,i4,i5,i6,i7;
  1388. int j0,j1,j2,j3,j4,j5,j6,j7;
  1389. int ia,ib,ic,id,ie,iF;
  1390. int ja,jb,jc,jd,je,jf;
  1391. int i,j,k,ijk,l,m;
  1392. int ibase,jbase;
  1393. int iink,jink;
  1394. int jump;
  1395. int kstop;
  1396. double c1,c2,c3,c4,c5;
  1397. double s1,s2,s3,s4,s5;
  1398. double kpidn;
  1399. double angle;
  1400. double qqrt5;
  1401. double ssin36;
  1402. double ssin72;
  1403. double pin;
  1404. double a10,a11,a20,a21;
  1405. double b10,b11,b20,b21;
  1406. m = n / ifac;
  1407. iink = la;
  1408. jink = la;
  1409. jump = (ifac-1) * jink;
  1410. kstop = (n-ifac) / (2*ifac);
  1411. pin = 2.0 * M_PI / n;
  1412. ibase = 0;
  1413. jbase = 0;
  1414. switch (ifac)
  1415. {
  1416. case 2:
  1417. {
  1418. double a0m1,b0p1;
  1419. i0 = j0 = 0;
  1420. i1 = i0 + (m+m-la);
  1421. j1 = j0 + jink;
  1422. if (la != m)
  1423. {
  1424. LOOP
  1425. c[j0+j] = a[i0+i] + a[i1+i];
  1426. c[j1+j] = a[i0+i] - a[i1+i];
  1427. ENDL
  1428. i0 += iink;
  1429. iink += iink;
  1430. i1 -= iink;
  1431. ibase = 0;
  1432. jbase += jump;
  1433. jump += jump + jink;
  1434. if (i0 != i1)
  1435. {
  1436. FORK
  1437. angle = k * pin;
  1438. c1 = cos(angle);
  1439. s1 = sin(angle);
  1440. ibase = 0;
  1441. LOOP
  1442. a0m1 = a[i0+i] - a[i1+i];
  1443. b0p1 = b[i0+i] + b[i1+i];
  1444. c[j0+j] = a[i0+i] + a[i1+i];
  1445. d[j0+j] = b[i0+i] - b[i1+i];
  1446. c[j1+j] = c1 * a0m1 - s1 * b0p1;
  1447. d[j1+j] = s1 * a0m1 + c1 * b0p1;
  1448. ENDL
  1449. i0 += iink;
  1450. i1 -= iink;
  1451. jbase += jump;
  1452. } /* End FORK */
  1453. if (i0 > i1) return 0;
  1454. } /* End (i0 != i1) */
  1455. ibase = 0;
  1456. LOOP
  1457. c[j0+j] = a[i0+i];
  1458. c[j1+j] = -b[i0+i];
  1459. ENDL
  1460. }
  1461. else /* (la != m) */ {
  1462. LOOP
  1463. c[j0+j] = 2.0 * (a[i0+i] + a[i1+i]);
  1464. c[j1+j] = 2.0 * (a[i0+i] - a[i1+i]);
  1465. ENDL
  1466. }
  1467. return 0;
  1468. }
  1469. case 3: {
  1470. double afa1,a1p2,a1m2,a0mm,a0mp;
  1471. double bfa1,b1p2,b1m2,b0mm,b0mp;
  1472. i0 = j0 = 0 ;
  1473. i1 = i0 + (m+m-la);
  1474. i2 = i1;
  1475. j1 = j0 + jink;
  1476. j2 = j1 + jink;
  1477. if (la != m) {
  1478. LOOP
  1479. afa1 = a[i0+i] - 0.5 * a[i1+i];
  1480. bfa1 = S60 * b[i1+i];
  1481. c[j0+j] = a[i0+i] + a[i1+i];
  1482. c[j1+j] = afa1 - bfa1;
  1483. c[j2+j] = afa1 + bfa1;
  1484. ENDL
  1485. i0 += iink;
  1486. iink += iink;
  1487. i1 += iink;
  1488. i2 -= iink;
  1489. jbase += jump;
  1490. jump += jump + jink;
  1491. if (i0 != i2) {
  1492. FORK
  1493. angle = k * pin;
  1494. c1 = cos(angle);
  1495. s1 = sin(angle);
  1496. angle += angle;
  1497. c2 = cos(angle);
  1498. s2 = sin(angle);
  1499. ibase = 0;
  1500. LOOP
  1501. a1p2 = a[i0+i] - 0.5 * (a[i1+i] + a[i2+i]);
  1502. b1m2 = b[i0+i] - 0.5 * (b[i1+i] - b[i2+i]);
  1503. a1m2 = S60 * (a[i1+i] - a[i2+i]);
  1504. b1p2 = S60 * (b[i1+i] + b[i2+i]);
  1505. a0mm = a1p2 - b1p2;
  1506. a0mp = a1p2 + b1p2;
  1507. b0mm = b1m2 - a1m2;
  1508. b0mp = b1m2 + a1m2;
  1509. c[j0+j] = a[i0+i] + a[i1+i] + a[i2+i];
  1510. d[j0+j] = b[i0+i] + b[i1+i] - b[i2+i];
  1511. c[j1+j] = c1 * a0mm - s1 * b0mp;
  1512. d[j1+j] = s1 * a0mm + c1 * b0mp;
  1513. c[j2+j] = c2 * a0mp - s2 * b0mm;
  1514. d[j2+j] = s2 * a0mp + c2 * b0mm;
  1515. ENDL
  1516. i0 += iink;
  1517. i1 += iink;
  1518. i2 -= iink;
  1519. jbase += jump;
  1520. } /* End FORK */
  1521. if (i0 > i2) return 0;
  1522. } /* End (i0 != i2) */
  1523. ibase=0;
  1524. LOOP
  1525. a0mp = 0.5 * a[i0+i];
  1526. b0mp = S60 * b[i0+i];
  1527. c[j0+j] = a[i0+i] + a[i1+i];
  1528. c[j1+j] = a0mp - a[i1+i] - b0mp;
  1529. c[j2+j] = a[i1+i] - a0mp - b0mp;
  1530. ENDL
  1531. }
  1532. else /* (la != m) */ {
  1533. LOOP
  1534. a0mp = 2.0 * a[i0+i] - a[i1+i];
  1535. b0mp = D60 * b[i1+i];
  1536. c[j0+j] = 2.0 * (a[i0+i] + a[i1+i]);
  1537. c[j1+j] = a0mp - b0mp;
  1538. c[j2+j] = a0mp + b0mp;
  1539. ENDL
  1540. }
  1541. return 0;
  1542. }
  1543. case 4: {
  1544. double a0m1,a0p2,a1p3,a0m2,a1m3,a0p2ma1p3,a0m2pb1p3,a0m2mb1p3;
  1545. double b0p1,b0p2,b1p3,b0m2,b1m3,b0p2pa1m3,b0p2ma1m3,b0m2mb1m3;
  1546. i0 = j0 = 0;
  1547. i1 = i3 = i0 + (m+m-la);
  1548. i2 = i1 + (m+m);
  1549. j1 = j0 + jink;
  1550. j2 = j1 + jink;
  1551. j3 = j2 + jink;
  1552. if (la != m) {
  1553. LOOP
  1554. a0p2 = a[i0+i] + a[i2+i];
  1555. a0m2 = a[i0+i] - a[i2+i];
  1556. c[j0+j] = a0p2 + a[i1+i];
  1557. c[j1+j] = a0m2 - b[i1+i];
  1558. c[j2+j] = a0p2 - a[i1+i];
  1559. c[j3+j] = a0m2 + b[i1+i];
  1560. ENDL
  1561. i0 += iink;
  1562. iink += iink;
  1563. i1 += iink;
  1564. i2 -= iink;
  1565. i3 -= iink;
  1566. jbase += jump;
  1567. jump += jump + jink;
  1568. if (i1 != i2) {
  1569. FORK
  1570. angle = kpidn = k * pin;
  1571. c1 = cos(angle);
  1572. s1 = sin(angle);
  1573. angle += kpidn;
  1574. c2 = cos(angle);
  1575. s2 = sin(angle);
  1576. angle += kpidn;
  1577. c3 = cos(angle);
  1578. s3 = sin(angle);
  1579. ibase=0;
  1580. LOOP
  1581. a0p2 = a[i0+i] + a[i2+i];
  1582. a0m2 = a[i0+i] - a[i2+i];
  1583. a1p3 = a[i1+i] + a[i3+i];
  1584. a1m3 = a[i1+i] - a[i3+i];
  1585. b0p2 = b[i0+i] + b[i2+i];
  1586. b0m2 = b[i0+i] - b[i2+i];
  1587. b1p3 = b[i1+i] + b[i3+i];
  1588. b1m3 = b[i1+i] - b[i3+i];
  1589. a0p2ma1p3 = a0p2 - a1p3;
  1590. a0m2pb1p3 = a0m2 + b1p3;
  1591. a0m2mb1p3 = a0m2 - b1p3;
  1592. b0p2pa1m3 = b0p2 + a1m3;
  1593. b0p2ma1m3 = b0p2 - a1m3;
  1594. b0m2mb1m3 = b0m2 - b1m3;
  1595. c[j0+j] = a0p2 + a1p3;
  1596. d[j0+j] = b0m2 + b1m3;
  1597. c[j2+j] = c2 * a0p2ma1p3 - s2 * b0m2mb1m3;
  1598. d[j2+j] = s2 * a0p2ma1p3 + c2 * b0m2mb1m3;
  1599. c[j1+j] = c1 * a0m2mb1p3 - s1 * b0p2pa1m3;
  1600. d[j1+j] = s1 * a0m2mb1p3 + c1 * b0p2pa1m3;
  1601. c[j3+j] = c3 * a0m2pb1p3 - s3 * b0p2ma1m3;
  1602. d[j3+j] = s3 * a0m2pb1p3 + c3 * b0p2ma1m3;
  1603. ENDL
  1604. i0 += iink;
  1605. i1 += iink;
  1606. i2 -= iink;
  1607. i3 -= iink;
  1608. jbase += jump;
  1609. } /* End FORK */
  1610. if (i1 > i2) return 0;
  1611. } /* End (i1 != i2) */
  1612. ibase=0;
  1613. LOOP
  1614. a0m1 = a[i0+i] - a[i1+i];
  1615. b0p1 = b[i0+i] + b[i1+i];
  1616. c[j0+j] = a[i0+i] + a[i1+i];
  1617. c[j2+j] = b[i1+i] - b[i0+i];
  1618. c[j1+j] = SQ2 * (a0m1 - b0p1);
  1619. c[j3+j] = -SQ2 * (a0m1 + b0p1);
  1620. ENDL
  1621. }
  1622. else /* (la != m) */ {
  1623. LOOP
  1624. a0p2 = a[i0+i] + a[i2+i];
  1625. a0m2 = a[i0+i] - a[i2+i];
  1626. c[j0+j] = 2.0 * (a0p2 + a[i1+i]);
  1627. c[j1+j] = 2.0 * (a0m2 - b[i1+i]);
  1628. c[j2+j] = 2.0 * (a0p2 - a[i1+i]);
  1629. c[j3+j] = 2.0 * (a0m2 + b[i1+i]);
  1630. ENDL
  1631. }
  1632. return 0;
  1633. }
  1634. case 5: {
  1635. double a1p2,a1m2,a0mm,a0mp,b136,b172,b236,b272;
  1636. i0 = j0 = 0;
  1637. i1 = i4 = i0 + (m+m-la);
  1638. i2 = i3 = i1 + (m+m);
  1639. j1 = j0 + jink;
  1640. j2 = j1 + jink;
  1641. j3 = j2 + jink;
  1642. j4 = j3 + jink;
  1643. if (la != m) {
  1644. LOOP
  1645. a1p2 = QUA * (a[i1+i] + a[i2+i]);
  1646. a1m2 = QT5 * (a[i1+i] - a[i2+i]);
  1647. a0mp = a[i0+i] - a1p2 + a1m2;
  1648. a0mm = a[i0+i] - a1p2 - a1m2;
  1649. b136 = b[i1+i] * S36;
  1650. b172 = b[i1+i] * S72;
  1651. b236 = b[i2+i] * S36;
  1652. b272 = b[i2+i] * S72;
  1653. c[j0+j] = a[i0+i] + a[i1+i] + a[i2+i];
  1654. c[j1+j] = a0mp - b172 - b236;
  1655. c[j2+j] = a0mm - b136 + b272;
  1656. c[j3+j] = a0mm + b136 - b272;
  1657. c[j4+j] = a0mp + b172 + b236;
  1658. ENDL
  1659. i0 += iink;
  1660. iink += iink;
  1661. i1 += iink;
  1662. i2 += iink;
  1663. i3 -= iink;
  1664. i4 -= iink;
  1665. jbase += jump;
  1666. jump += jump + jink;
  1667. if (i1 != i3) {
  1668. FORK
  1669. angle = kpidn = k * pin;
  1670. c1 = cos(angle);
  1671. s1 = sin(angle);
  1672. angle += kpidn;
  1673. c2 = cos(angle);
  1674. s2 = sin(angle);
  1675. angle += kpidn;
  1676. c3 = cos(angle);
  1677. s3 = sin(angle);
  1678. angle += kpidn;
  1679. c4 = cos(angle);
  1680. s4 = sin(angle);
  1681. ibase=0;
  1682. LOOP
  1683. a10=(a[i0+i]-0.25*((a[i1+i]+a[i4+i])+(a[i2+i]+a[i3+i])))
  1684. +QT5*((a[i1+i]+a[i4+i])-(a[i2+i]+a[i3+i]));
  1685. a20=(a[i0+i]-0.25*((a[i1+i]+a[i4+i])+(a[i2+i]+a[i3+i])))
  1686. -QT5*((a[i1+i]+a[i4+i])-(a[i2+i]+a[i3+i]));
  1687. b10=(b[i0+i]-0.25*((b[i1+i]-b[i4+i])+(b[i2+i]-b[i3+i])))
  1688. +QT5*((b[i1+i]-b[i4+i])-(b[i2+i]-b[i3+i]));
  1689. b20=(b[i0+i]-0.25*((b[i1+i]-b[i4+i])+(b[i2+i]-b[i3+i])))
  1690. -QT5*((b[i1+i]-b[i4+i])-(b[i2+i]-b[i3+i]));
  1691. a11=S72*(b[i1+i]+b[i4+i])+S36*(b[i2+i]+b[i3+i]);
  1692. a21=S36*(b[i1+i]+b[i4+i])-S72*(b[i2+i]+b[i3+i]);
  1693. b11=S72*(a[i1+i]-a[i4+i])+S36*(a[i2+i]-a[i3+i]);
  1694. b21=S36*(a[i1+i]-a[i4+i])-S72*(a[i2+i]-a[i3+i]);
  1695. c[j0+j]=a[i0+i]+((a[i1+i]+a[i4+i])+(a[i2+i]+a[i3+i]));
  1696. d[j0+j]=b[i0+i]+((b[i1+i]-b[i4+i])+(b[i2+i]-b[i3+i]));
  1697. c[j1+j]=c1*(a10-a11)-s1*(b10+b11);
  1698. d[j1+j]=s1*(a10-a11)+c1*(b10+b11);
  1699. c[j4+j]=c4*(a10+a11)-s4*(b10-b11);
  1700. d[j4+j]=s4*(a10+a11)+c4*(b10-b11);
  1701. c[j2+j]=c2*(a20-a21)-s2*(b20+b21);
  1702. d[j2+j]=s2*(a20-a21)+c2*(b20+b21);
  1703. c[j3+j]=c3*(a20+a21)-s3*(b20-b21);
  1704. d[j3+j]=s3*(a20+a21)+c3*(b20-b21);
  1705. ENDL
  1706. i0 += iink;
  1707. i1 += iink;
  1708. i2 += iink;
  1709. i3 -= iink;
  1710. i4 -= iink;
  1711. jbase += jump;
  1712. } /* End FORK */
  1713. if (i1 > i3) return 0;
  1714. } /* End (i1 != i3) */
  1715. ibase=0;
  1716. LOOP
  1717. c[j0+j] = a[i0+i] + a[i1+i] + a[i2+i];
  1718. c[j1+j] = (QT5 * (a[i0+i]-a[i1+i])
  1719. + (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
  1720. - (S36 * b[i0+i]+S72*b[i1+i]);
  1721. c[j4+j] =-(QT5 * (a[i0+i]-a[i1+i])
  1722. + (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
  1723. - (S36 * b[i0+i]+S72*b[i1+i]);
  1724. c[j2+j] = (QT5 * (a[i0+i]-a[i1+i])
  1725. - (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
  1726. - (S72 * b[i0+i]-S36*b[i1+i]);
  1727. c[j3+j] =-(QT5 * (a[i0+i]-a[i1+i])
  1728. - (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
  1729. - (S72 * b[i0+i]-S36*b[i1+i]);
  1730. ENDL
  1731. } else {
  1732. qqrt5 = 2.0 * QT5 ;
  1733. ssin36 = 2.0 * S36;
  1734. ssin72 = 2.0 * S72;
  1735. LOOP
  1736. c[j0+j]= 2.0 *(a[i0+i]+a[i1+i]+a[i2+i]);
  1737. c[j1+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
  1738. +qqrt5*(a[i1+i]-a[i2+i]))-(ssin72*b[i1+i]+ssin36*b[i2+i]);
  1739. c[j2+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
  1740. -qqrt5*(a[i1+i]-a[i2+i]))-(ssin36*b[i1+i]-ssin72*b[i2+i]);
  1741. c[j3+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
  1742. -qqrt5*(a[i1+i]-a[i2+i]))+(ssin36*b[i1+i]-ssin72*b[i2+i]);
  1743. c[j4+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
  1744. +qqrt5*(a[i1+i]-a[i2+i]))+(ssin72*b[i1+i]+ssin36*b[i2+i]);
  1745. ENDL
  1746. }
  1747. return 0;
  1748. }
  1749. case 6: {
  1750. ia = 0;
  1751. ib = ia+(2*m-la);
  1752. ic = ib+2*m;
  1753. id = ic+2*m;
  1754. ie = ic;
  1755. iF = ib;
  1756. ja = 0;
  1757. jb = ja+jink;
  1758. jc = jb+jink;
  1759. jd = jc+jink;
  1760. je = jd+jink;
  1761. jf = je+jink;
  1762. if (la != m) /* go to 690 */ {
  1763. LOOP
  1764. c[ja+j] = (a[ia+i]+a[id+i]) + (a[ib+i]+a[ic+i]) ;
  1765. c[jd+j] = (a[ia+i]-a[id+i]) - (a[ib+i]-a[ic+i]) ;
  1766. c[jb+j] = ((a[ia+i]-a[id+i]) +0.5*(a[ib+i]-a[ic+i]))
  1767. - S60*(b[ib+i]+b[ic+i]);
  1768. c[jf+j] = ((a[ia+i]-a[id+i]) +0.5*(a[ib+i]-a[ic+i]))
  1769. + S60*(b[ib+i]+b[ic+i]);
  1770. c[jc+j] = ((a[ia+i]+a[id+i]) -0.5*(a[ib+i]+a[ic+i]))
  1771. - S60*(b[ib+i]-b[ic+i]);
  1772. c[je+j] = ((a[ia+i]+a[id+i]) -0.5*(a[ib+i]+a[ic+i]))
  1773. + S60*(b[ib+i]-b[ic+i]);
  1774. ENDL
  1775. ia += iink;
  1776. iink += iink;
  1777. ib += iink;
  1778. ic += iink;
  1779. id -= iink;
  1780. ie -= iink;
  1781. iF -= iink;
  1782. jbase += jump;
  1783. jump += jump+jink;
  1784. if (ic != id) /* go to 660 */ {
  1785. FORK
  1786. angle = kpidn = k * pin;
  1787. c1 = cos(angle);
  1788. s1 = sin(angle);
  1789. angle += kpidn;
  1790. c2 = cos(angle);
  1791. s2 = sin(angle);
  1792. angle += kpidn;
  1793. c3 = cos(angle);
  1794. s3 = sin(angle);
  1795. angle += kpidn;
  1796. c4 = cos(angle);
  1797. s4 = sin(angle);
  1798. angle += kpidn;
  1799. c5 = cos(angle);
  1800. s5 = sin(angle);
  1801. ibase=0;
  1802. LOOP
  1803. a11 = a[ie+i] + a[ib+i] + a[ic+i] + a[iF+i];
  1804. a20 = a[ia+i] + a[id+i] - 0.5 * a11;
  1805. a21 = S60*((a[ie+i]+a[ib+i])-(a[ic+i]+a[iF+i]));
  1806. b11 = b[ib+i] - b[ie+i] + b[ic+i] - b[iF+i];
  1807. b20 = b[ia+i] - b[id+i] - 0.5 * b11;
  1808. b21 = S60*((b[ib+i]-b[ie+i])-(b[ic+i]-b[iF+i]));
  1809. c[ja+j] = a[ia+i] + a[id+i] + a11;
  1810. d[ja+j] = b[ia+i] - b[id+i] + b11;
  1811. c[jc+j] = c2*(a20-b21)-s2*(b20+a21);
  1812. d[jc+j] = s2*(a20-b21)+c2*(b20+a21);
  1813. c[je+j] = c4*(a20+b21)-s4*(b20-a21);
  1814. d[je+j] = s4*(a20+b21)+c4*(b20-a21);
  1815. a11 = (a[ie+i]-a[ib+i]) + (a[ic+i]-a[iF+i]);
  1816. b11 = (b[ie+i]+b[ib+i]) - (b[ic+i]+b[iF+i]);
  1817. a20 = (a[ia+i]-a[id+i]) - 0.5 * a11;
  1818. a21 = S60 * ((a[ie+i]-a[ib+i]) - (a[ic+i]-a[iF+i]));
  1819. b20 = (b[ia+i]+b[id+i]) + 0.5 * b11;
  1820. b21 = S60 * ((b[ie+i]+b[ib+i]) + (b[ic+i]+b[iF+i]));
  1821. c[jd+j] = c3*(a[ia+i] - a[id+i] + a11)
  1822. - s3*(b[ia+i] + b[id+i] - b11);
  1823. d[jd+j] = s3*(a[ia+i] - a[id+i] + a11)
  1824. + c3*(b[ia+i] + b[id+i] - b11);
  1825. c[jb+j] = c1*(a20-b21)-s1*(b20-a21);
  1826. d[jb+j] = s1*(a20-b21)+c1*(b20-a21);
  1827. c[jf+j] = c5*(a20+b21)-s5*(b20+a21);
  1828. d[jf+j] = s5*(a20+b21)+c5*(b20+a21);
  1829. ENDL
  1830. ia += iink;
  1831. ib += iink;
  1832. ic += iink;
  1833. id -= iink;
  1834. ie -= iink;
  1835. iF -= iink;
  1836. jbase += jump;
  1837. }
  1838. if (ic > id) return 0;
  1839. }
  1840. ibase=0;
  1841. LOOP
  1842. c[ja+j]= a[ib+i] + (a[ia+i] + a[ic+i]);
  1843. c[jd+j]= b[ib+i] - (b[ia+i] + b[ic+i]);
  1844. c[jb+j]= (S60*(a[ia+i]-a[ic+i]))-(0.5*(b[ia+i]+b[ic+i])+b[ib+i]);
  1845. c[jf+j]=-(S60*(a[ia+i]-a[ic+i]))-(0.5*(b[ia+i]+b[ic+i])+b[ib+i]);
  1846. c[jc+j]= S60*(b[ic+i]-b[ia+i]) +(0.5*(a[ia+i]+a[ic+i])-a[ib+i]);
  1847. c[je+j]= S60*(b[ic+i]-b[ia+i]) -(0.5*(a[ia+i]+a[ic+i])-a[ib+i]);
  1848. ENDL
  1849. } else {
  1850. LOOP
  1851. c[ja+j]=(2.0*(a[ia+i]+a[id+i]))+(2.0*(a[ib+i]+a[ic+i]));
  1852. c[jd+j]=(2.0*(a[ia+i]-a[id+i]))-(2.0*(a[ib+i]-a[ic+i]));
  1853. c[jb+j]=(2.0*(a[ia+i]-a[id+i])+(a[ib+i]-a[ic+i]))
  1854. -(D60*(b[ib+i]+b[ic+i]));
  1855. c[jf+j]=(2.0*(a[ia+i]-a[id+i])+(a[ib+i]-a[ic+i]))
  1856. +(D60*(b[ib+i]+b[ic+i]));
  1857. c[jc+j]=(2.0*(a[ia+i]+a[id+i])-(a[ib+i]+a[ic+i]))
  1858. -(D60*(b[ib+i]-b[ic+i]));
  1859. c[je+j]=(2.0*(a[ia+i]+a[id+i])-(a[ib+i]+a[ic+i]))
  1860. +(D60*(b[ib+i]-b[ic+i]));
  1861. ENDL
  1862. }
  1863. return 0;
  1864. }
  1865. case 8: {
  1866. double a0p7,a1p5,a2p6,p073,p074,p152;
  1867. double a0m7,a1m5,a2m6,m073,m074,m152;
  1868. if (la != m) return 3;
  1869. i0 = 0;
  1870. i1 = i0 + iink;
  1871. i2 = i1 + iink;
  1872. i3 = i2 + iink;
  1873. i4 = i3 + iink;
  1874. i5 = i4 + iink;
  1875. i6 = i5 + iink;
  1876. i7 = i6 + iink;
  1877. j0 = 0;
  1878. j1 = j0 + jink;
  1879. j2 = j1 + jink;
  1880. j3 = j2 + jink;
  1881. j4 = j3 + jink;
  1882. j5 = j4 + jink;
  1883. j6 = j5 + jink;
  1884. j7 = j6 + jink;
  1885. LOOP
  1886. a0p7 = a[i0+i] + a[i7+i];
  1887. a0m7 = a[i0+i] - a[i7+i];
  1888. a1p5 = a[i1+i] + a[i5+i];
  1889. a1m5 = a[i1+i] - a[i5+i];
  1890. a2p6 = a[i2+i] + a[i6+i];
  1891. a2m6 = a[i2+i] - a[i6+i];
  1892. p073 = a0p7 + a[i3+i];
  1893. m073 = a0p7 - a[i3+i];
  1894. p074 = 2.0 * (a0m7 + a[i4+i]);
  1895. m074 = 2.0 * (a0m7 - a[i4+i]);
  1896. p152 = M_SQRT2 * (a1m5 + a2p6);
  1897. m152 = M_SQRT2 * (a1m5 - a2p6);
  1898. c[j0+j] = 2.0 * (p073 + a1p5);
  1899. c[j4+j] = 2.0 * (p073 - a1p5);
  1900. c[j2+j] = 2.0 * (m073 - a2m6);
  1901. c[j6+j] = 2.0 * (m073 + a2m6);
  1902. c[j1+j] = m074 + m152;
  1903. c[j5+j] = m074 - m152;
  1904. c[j3+j] = p074 - p152;
  1905. c[j7+j] = p074 + p152;
  1906. ENDL
  1907. }
  1908. }
  1909. return 0;
  1910. }
  1911. int qpassc(double *a, double *b, double *c, double *d,
  1912. int inc3, int inc4,
  1913. int lot , int n , int ifac, int la )
  1914. {
  1915. /*
  1916. qpassc - performs one pass through data as part;
  1917. of multiple real fft (fourier analysis) routine;
  1918. a is first real input vector;
  1919. b is equivalent to a + ifac * la
  1920. c is first real output vector;
  1921. d is equivalent to c + la
  1922. inc3 is the increment between input vectors a;
  1923. inc4 is the increment between output vectors c;
  1924. lot is the number of vectors;
  1925. n is the length of the vectors;
  1926. ifac is the current factor of n;
  1927. la is the product of previous factors;
  1928. qpassc returns an error indicator:;
  1929. 0 - pass completed without error;
  1930. 2 - ifac not catered for;
  1931. 3 - ifac only catered for if la=n/ifac;
  1932. */
  1933. int i0,i1,i2,i3,i4,i5,i6,i7;
  1934. int j0,j1,j2,j3,j4,j5,j6,j7;
  1935. int ia,ib,ic;
  1936. int ja,jb,jc;
  1937. int i,j,k;
  1938. int ibase,jbase;
  1939. int iink,jink;
  1940. int ijk;
  1941. int jump;
  1942. int kstop;
  1943. int l;
  1944. int m;
  1945. double a0,a1,a2,a3;
  1946. double b0,b1,b2,b3;
  1947. double c1,c2,c3,c4,c5;
  1948. double s1,s2,s3,s4,s5;
  1949. double w,x,y,z;
  1950. double angle,kpidn,pin;
  1951. m = n / ifac;
  1952. iink = la;
  1953. jink = la;
  1954. jump = (ifac-1) * iink;
  1955. kstop = (n-ifac) / (2*ifac);
  1956. pin = 2.0 * M_PI / n;
  1957. ibase = 0;
  1958. jbase = 0;
  1959. switch (ifac) {
  1960. case 2: {
  1961. i0 = j0 = 0;
  1962. i1 = i0 + iink;
  1963. j1 = j0 + (m+m-la);
  1964. if (la != m) {
  1965. LOOP
  1966. c[j0+j] = a[i0+i] + a[i1+i];
  1967. c[j1+j] = a[i0+i] - a[i1+i];
  1968. ENDL
  1969. j0 += jink;
  1970. jink += jink;
  1971. j1 -= jink;
  1972. ibase += jump;
  1973. jump += jump + iink;
  1974. if (j0 != j1) {
  1975. FORK
  1976. angle = k * pin;
  1977. c1 = cos(angle);
  1978. s1 = sin(angle);
  1979. jbase = 0;
  1980. LOOP
  1981. c[j0+j] = a[i0+i] + c1 * a[i1+i] + s1 * b[i1+i];
  1982. c[j1+j] = a[i0+i] - c1 * a[i1+i] - s1 * b[i1+i];
  1983. d[j0+j] = c1 * b[i1+i] - s1 * a[i1+i] + b[i0+i];
  1984. d[j1+j] = c1 * b[i1+i] - s1 * a[i1+i] - b[i0+i];
  1985. ENDL
  1986. j0 += jink;
  1987. j1 -= jink;
  1988. ibase += jump;
  1989. } /* End FORK */
  1990. if (j0 > j1) return 0;
  1991. } /* End (i0 != i1) */
  1992. jbase = 0;
  1993. LOOP
  1994. c[j0+j] = a[i0+i];
  1995. d[j1+j] = -a[i1+i];
  1996. ENDL
  1997. }
  1998. else /* (la != m) */ {
  1999. z = 1.0 / n;
  2000. LOOP
  2001. c[j0+j] = z * (a[i0+i] + a[i1+i]);
  2002. c[j1+j] = z * (a[i0+i] - a[i1+i]);
  2003. ENDL
  2004. }
  2005. return 0;
  2006. }
  2007. case 3: {
  2008. ia = 0;
  2009. ib = ia + iink;
  2010. ic = ib + iink;
  2011. ja = 0;
  2012. jb = ja + (m+m-la);
  2013. jc = jb;
  2014. if (la != m) /* else 390 */ {
  2015. LOOP
  2016. c[ja+j] = a[ia+i] + a[ib+i] + a[ic+i];
  2017. c[jb+j] = a[ia+i] - 0.5 * (a[ib+i] + a[ic+i]);
  2018. d[jb+j] = S60 * (a[ic+i] - a[ib+i]);
  2019. ENDL
  2020. ja += jink;
  2021. jink += jink;
  2022. jb += jink;
  2023. jc -= jink;
  2024. ibase += jump;
  2025. jump += jump + iink;
  2026. if (ja != jc) /* else 360 */ {
  2027. FORK
  2028. angle = k * pin;
  2029. c1 = cos(angle);
  2030. s1 = sin(angle);
  2031. angle += angle;
  2032. c2 = cos(angle);
  2033. s2 = sin(angle);
  2034. jbase = 0;
  2035. LOOP
  2036. a1 = c1 * a[ib+i] + s1 * b[ib+i] + c2 * a[ic+i] + s2 * b[ic+i];
  2037. b1 = c1 * b[ib+i] - s1 * a[ib+i] + c2 * b[ic+i] - s2 * a[ic+i];
  2038. a2 = a[ia+i] - 0.5 * a1;
  2039. b2 = b[ia+i] - 0.5 * b1;
  2040. a3 = S60 * (c1 * a[ib+i] + s1 * b[ib+i] - c2 * a[ic+i] - s2 * b[ic+i]);
  2041. b3 = S60 * (c1 * b[ib+i] - s1 * a[ib+i] - c2 * b[ic+i] + s2 * a[ic+i]);
  2042. c[ja+j] = a[ia+i] + a1;
  2043. d[ja+j] = b[ia+i] + b1;
  2044. c[jb+j] = a2 + b3;
  2045. d[jb+j] = b2 - a3;
  2046. c[jc+j] = a2 - b3;
  2047. d[jc+j] =-b2 - a3;
  2048. ENDL
  2049. ja += jink;
  2050. jb += jink;
  2051. jc -= jink;
  2052. ibase += jump;
  2053. } /* End FORK */
  2054. if (ja > jc) return 0;
  2055. } /* End (ia != ic) */
  2056. jbase = 0;
  2057. LOOP
  2058. /* soweit */
  2059. c[ja+j] = a[ia+i] + 0.5 * (a[ib+i] - a[ic+i]);
  2060. d[ja+j] =-S60 * (a[ib+i] + a[ic+i]);
  2061. c[jb+j] = a[ia+i] - a[ib+i] + a[ic+i];
  2062. ENDL
  2063. }
  2064. else /* (la != m) */ {
  2065. z = 1.0 / n;
  2066. y = S60 / n;
  2067. LOOP
  2068. c[ja+j] = z * (a[ia+i] + a[ib+i] + a[ic+i]);
  2069. c[jb+j] = z * (a[ia+i] - 0.5 * (a[ib+i] + a[ic+i]));
  2070. d[jb+j] = y * (a[ic+i] - a[ib+i]);
  2071. ENDL
  2072. }
  2073. return 0;
  2074. }
  2075. case 4: {
  2076. double a0p2,a1p3;
  2077. i0 = 0;
  2078. i1 = i0 + iink;
  2079. i2 = i1 + iink;
  2080. i3 = i2 + iink;
  2081. j0 = 0;
  2082. j1 = j0 + (m+m-la);
  2083. j2 = j1 + (m+m );
  2084. j3 = j1;
  2085. if (la != m) /*else go to 490 */ {
  2086. LOOP
  2087. a0p2 = a[i0+i] + a[i2+i];
  2088. a1p3 = a[i1+i] + a[i3+i];
  2089. c[j0+j] = a0p2 + a1p3;
  2090. c[j2+j] = a0p2 - a1p3;
  2091. c[j1+j] = a[i0+i] - a[i2+i];
  2092. d[j1+j] = a[i3+i] - a[i1+i];
  2093. ENDL
  2094. j0 += jink;
  2095. jink += jink;
  2096. j1 += jink;
  2097. j2 -= jink;
  2098. j3 -= jink;
  2099. ibase += jump;
  2100. jump += jump + iink;
  2101. if (j1 != j2) /* else go to 460; */ {
  2102. FORK
  2103. angle = kpidn = k * pin;
  2104. c1 = cos(angle);
  2105. s1 = sin(angle);
  2106. angle += kpidn;
  2107. c2 = cos(angle);
  2108. s2 = sin(angle);
  2109. angle += kpidn;
  2110. c3 = cos(angle);
  2111. s3 = sin(angle);
  2112. jbase=0;
  2113. LOOP
  2114. a0 = a[i0+i] + c2 * a[i2+i] + s2 * b[i2+i];
  2115. a2 = a[i0+i] - c2 * a[i2+i] - s2 * b[i2+i];
  2116. b0 = b[i0+i] + c2 * b[i2+i] - s2 * a[i2+i];
  2117. b2 = b[i0+i] - c2 * b[i2+i] + s2 * a[i2+i];
  2118. a1 = c1*a[i1+i] + s1*b[i1+i] + c3*a[i3+i] + s3*b[i3+i];
  2119. a3 = c1*a[i1+i] + s1*b[i1+i] - c3*a[i3+i] - s3*b[i3+i];
  2120. b1 = c1*b[i1+i] - s1*a[i1+i] + c3*b[i3+i] - s3*a[i3+i];
  2121. b3 = c1*b[i1+i] - s1*a[i1+i] - c3*b[i3+i] + s3*a[i3+i];
  2122. c[j0+j] = a0 + a1;
  2123. c[j2+j] = a0 - a1;
  2124. d[j0+j] = b0 + b1;
  2125. d[j2+j] = b1 - b0;
  2126. c[j1+j] = a2 + b3;
  2127. c[j3+j] = a2 - b3;
  2128. d[j1+j] = b2 - a3;
  2129. d[j3+j] =-b2 - a3;
  2130. ENDL
  2131. j0 += jink;
  2132. j1 += jink;
  2133. j2 -= jink;
  2134. j3 -= jink;
  2135. ibase += jump;
  2136. } /* End FORK */
  2137. if (j1 > j2) return 0;
  2138. } /* End (i1 != i2) */
  2139. jbase=0;
  2140. LOOP
  2141. c[j0+j] = a[i0+i] + SQ2 * (a[i1+i] - a[i3+i]);
  2142. c[j1+j] = a[i0+i] - SQ2 * (a[i1+i] - a[i3+i]);
  2143. d[j0+j] =-a[i2+i] - SQ2 * (a[i1+i] + a[i3+i]);
  2144. d[j1+j] = a[i2+i] - SQ2 * (a[i1+i] + a[i3+i]);
  2145. ENDL
  2146. }
  2147. else /* (la != m) */ {
  2148. z = 1.0 / n;
  2149. LOOP
  2150. a0p2 = a[i0+i] + a[i2+i];
  2151. a1p3 = a[i1+i] + a[i3+i];
  2152. c[j0+j] = z * (a0p2 + a1p3);
  2153. c[j2+j] = z * (a0p2 - a1p3);
  2154. c[j1+j] = z * (a[i0+i] - a[i2+i]);
  2155. d[j1+j] = z * (a[i3+i] - a[i1+i]);
  2156. ENDL
  2157. }
  2158. return 0;
  2159. }
  2160. case 5: {
  2161. double a1p4,a2p3,b1p4,b2p3,a025,b025,asps,bsps,a0pq,b0pq;
  2162. double a1m4,a2m3,b1m4,b2m3,aqrt,bqrt,asms,bsms,a0mq,b0mq;
  2163. i0 = 0;
  2164. i1 = i0 + iink;
  2165. i2 = i1 + iink;
  2166. i3 = i2 + iink;
  2167. i4 = i3 + iink;
  2168. j0 = 0;
  2169. j1 = j0 + (m+m-la);
  2170. j2 = j1 + (m+m);
  2171. j3 = j2;
  2172. j4 = j1;
  2173. if (la != m) /* else go to 590; */ {
  2174. LOOP
  2175. a1p4 = a[i1+i] + a[i4+i];
  2176. a1m4 = a[i1+i] - a[i4+i];
  2177. a2p3 = a[i2+i] + a[i3+i];
  2178. a2m3 = a[i2+i] - a[i3+i];
  2179. a025 = a[i0+i] - 0.25 * (a1p4 + a2p3);
  2180. aqrt = QT5 * (a1p4 - a2p3);
  2181. c[j0+j] = a[i0+i] + a1p4 + a2p3;
  2182. c[j1+j] = a025 + aqrt;
  2183. c[j2+j] = a025 - aqrt;
  2184. d[j1+j] = -S72 * a1m4 - S36 * a2m3;
  2185. d[j2+j] = -S36 * a1m4 + S72 * a2m3;
  2186. ENDL
  2187. j0 += jink;
  2188. jink += jink;
  2189. j1 += jink;
  2190. j2 += jink;
  2191. j3 -= jink;
  2192. j4 -= jink;
  2193. ibase += jump;
  2194. jump += jump + iink;
  2195. if (j1 != j3) {
  2196. FORK
  2197. angle = kpidn = k * pin;
  2198. c1 = cos(angle);
  2199. s1 = sin(angle);
  2200. angle += kpidn;
  2201. c2 = cos(angle);
  2202. s2 = sin(angle);
  2203. angle += kpidn;
  2204. c3 = cos(angle);
  2205. s3 = sin(angle);
  2206. angle += kpidn;
  2207. c4 = cos(angle);
  2208. s4 = sin(angle);
  2209. jbase=0;
  2210. LOOP
  2211. a1p4 = c1*a[i1+i] + s1*b[i1+i] + c4*a[i4+i] + s4*b[i4+i];
  2212. a1m4 = c1*a[i1+i] + s1*b[i1+i] - c4*a[i4+i] - s4*b[i4+i];
  2213. a2p3 = c2*a[i2+i] + s2*b[i2+i] + c3*a[i3+i] + s3*b[i3+i];
  2214. a2m3 = c2*a[i2+i] + s2*b[i2+i] - c3*a[i3+i] - s3*b[i3+i];
  2215. b1p4 = c1*b[i1+i] - s1*a[i1+i] + c4*b[i4+i] - s4*a[i4+i];
  2216. b1m4 = c1*b[i1+i] - s1*a[i1+i] - c4*b[i4+i] + s4*a[i4+i];
  2217. b2p3 = c2*b[i2+i] - s2*a[i2+i] + c3*b[i3+i] - s3*a[i3+i];
  2218. b2m3 = c2*b[i2+i] - s2*a[i2+i] - c3*b[i3+i] + s3*a[i3+i];
  2219. a025 = a[i0+i] - 0.25 * (a1p4 + a2p3);
  2220. aqrt = QT5 * (a1p4 - a2p3);
  2221. b025 = b[i0+i] - 0.25 * (b1p4 + b2p3);
  2222. bqrt = QT5 * (b1p4 - b2p3);
  2223. a0pq = a025 + aqrt;
  2224. a0mq = a025 - aqrt;
  2225. b0pq = b025 + bqrt;
  2226. b0mq = b025 - bqrt;
  2227. asps = S72 * a1m4 + S36 * a2m3;
  2228. asms = S36 * a1m4 - S72 * a2m3;
  2229. bsps = S72 * b1m4 + S36 * b2m3;
  2230. bsms = S36 * b1m4 - S72 * b2m3;
  2231. c[j0+j] = a[i0+i] + a1p4 + a2p3;
  2232. c[j1+j] = a0pq + bsps;
  2233. c[j2+j] = a0mq + bsms;
  2234. c[j3+j] = a0mq - bsms;
  2235. c[j4+j] = a0pq - bsps;
  2236. d[j0+j] = b[i0+i] + b1p4 + b2p3;
  2237. d[j1+j] = b0pq - asps;
  2238. d[j2+j] = b0mq - asms;
  2239. d[j3+j] =-b0mq - asms;
  2240. d[j4+j] =-b0pq - asps;
  2241. ENDL
  2242. j0 += jink;
  2243. j1 += jink;
  2244. j2 += jink;
  2245. j3 -= jink;
  2246. j4 -= jink;
  2247. ibase += jump;
  2248. } /* End FORK */
  2249. if (j1 > j3) return 0;
  2250. } /* End (jb != jd) */
  2251. jbase=0;
  2252. LOOP
  2253. a1p4 = a[i1+i] + a[i4+i];
  2254. a1m4 = a[i1+i] - a[i4+i];
  2255. a2p3 = a[i2+i] + a[i3+i];
  2256. a2m3 = a[i2+i] - a[i3+i];
  2257. a025 = a[i0+i] + 0.25 * (a1m4 - a2m3);
  2258. aqrt = QT5 * (a1m4 + a2m3);
  2259. c[j0+j] = a025 + aqrt;
  2260. c[j1+j] = a025 - aqrt;
  2261. c[j2+j] = a[i0+i] - a1m4 + a2m3;
  2262. d[j0+j] = -S36 * a1p4 - S72 * a2p3;
  2263. d[j1+j] = -S72 * a1p4 + S36 * a2p3;
  2264. ENDL
  2265. } else {
  2266. z = 1.0 / n;
  2267. y = QT5 / n;
  2268. x = S36 / n;
  2269. w = S72 / n;
  2270. LOOP
  2271. a1p4 = a[i1+i] + a[i4+i];
  2272. a1m4 = a[i1+i] - a[i4+i];
  2273. a2p3 = a[i2+i] + a[i3+i];
  2274. a2m3 = a[i2+i] - a[i3+i];
  2275. a025 = z * (a[i0+i] - 0.25 * (a1p4 + a2p3));
  2276. aqrt = y * (a1p4 - a2p3);
  2277. c[j0+j] = z * (a[i0+i] + a1p4 + a2p3);
  2278. c[j1+j] = a025 + aqrt;
  2279. c[j2+j] = a025 - aqrt;
  2280. d[j1+j] = -w * a1m4 - x * a2m3;
  2281. d[j2+j] = w * a2m3 - x * a1m4;
  2282. ENDL
  2283. }
  2284. return 0;
  2285. }
  2286. case 6: {
  2287. double ab1a,ab2a,ab3a,ab4a,ab5a;
  2288. double ab1b,ab2b,ab3b,ab4b,ab5b;
  2289. double a0p3,a1p4,a1p5,a2p4,a2p5;
  2290. double a0m3,a1m4,a1m5,a2m4,a2m5;
  2291. double b1p4,b2p5;
  2292. double b1m4,b2m5;
  2293. double ap05,bp05,ap60,bp60;
  2294. double am05,bm05,am60,bm60;
  2295. i0 = 0;
  2296. i1 = i0 + iink;
  2297. i2 = i1 + iink;
  2298. i3 = i2 + iink;
  2299. i4 = i3 + iink;
  2300. i5 = i4 + iink;
  2301. j0 = 0;
  2302. j1 = j0 + (m+m-la);
  2303. j2 = j1 + (m+m);
  2304. j3 = j2 + (m+m);
  2305. j4 = j2;
  2306. j5 = j1;
  2307. if (la != m) {
  2308. LOOP
  2309. a0p3 = a[i0+i] + a[i3+i];
  2310. a0m3 = a[i0+i] - a[i3+i];
  2311. a1p4 = a[i1+i] + a[i4+i];
  2312. a1m4 = a[i1+i] - a[i4+i];
  2313. a2p5 = a[i2+i] + a[i5+i];
  2314. a2m5 = a[i2+i] - a[i5+i];
  2315. c[j0+j] = a0p3 + a1p4 + a2p5;
  2316. c[j3+j] = a0m3 + a2m5 - a1m4;
  2317. c[j1+j] = a0m3 - 0.5 * (a2m5 - a1m4);
  2318. c[j2+j] = a0p3 - 0.5 * (a1p4 + a2p5);
  2319. d[j1+j] = S60 * (-a2m5 - a1m4);
  2320. d[j2+j] = S60 * ( a2p5 - a1p4);
  2321. ENDL
  2322. j0 += jink;
  2323. jink += jink;
  2324. j1 += jink;
  2325. j2 += jink;
  2326. j3 -= jink;
  2327. j4 -= jink;
  2328. j5 -= jink;
  2329. ibase += jump;
  2330. jump += jump+iink;
  2331. if (j2 != j3) {
  2332. FORK
  2333. angle = kpidn = k * pin;
  2334. c1 = cos(angle);
  2335. s1 = sin(angle);
  2336. angle += kpidn;
  2337. c2 = cos(angle);
  2338. s2 = sin(angle);
  2339. angle += kpidn;
  2340. c3 = cos(angle);
  2341. s3 = sin(angle);
  2342. angle += kpidn;
  2343. c4 = cos(angle);
  2344. s4 = sin(angle);
  2345. angle += kpidn;
  2346. c5 = cos(angle);
  2347. s5 = sin(angle);
  2348. jbase = 0;
  2349. LOOP
  2350. ab1a = c1 * a[i1+i] + s1 * b[i1+i];
  2351. ab1b = c1 * b[i1+i] - s1 * a[i1+i];
  2352. ab2a = c2 * a[i2+i] + s2 * b[i2+i];
  2353. ab2b = c2 * b[i2+i] - s2 * a[i2+i];
  2354. ab3a = c3 * a[i3+i] + s3 * b[i3+i];
  2355. ab3b = c3 * b[i3+i] - s3 * a[i3+i];
  2356. ab4a = c4 * a[i4+i] + s4 * b[i4+i];
  2357. ab4b = c4 * b[i4+i] - s4 * a[i4+i];
  2358. ab5a = c5 * a[i5+i] + s5 * b[i5+i];
  2359. ab5b = c5 * b[i5+i] - s5 * a[i5+i];
  2360. a1p4 = ab1a + ab4a;
  2361. a1m4 = ab1a - ab4a;
  2362. a2p5 = ab2a + ab5a;
  2363. a2m5 = ab2a - ab5a;
  2364. b1p4 = ab1b + ab4b;
  2365. b1m4 = ab1b - ab4b;
  2366. b2p5 = ab2b + ab5b;
  2367. b2m5 = ab2b - ab5b;
  2368. ap05 = a[i0+i] + ab3a - 0.5 * (a1p4 + a2p5);
  2369. bp05 = b[i0+i] + ab3b - 0.5 * (b1p4 + b2p5);
  2370. am05 = a[i0+i] - ab3a - 0.5 * (a2m5 - a1m4);
  2371. bm05 =-b[i0+i] + ab3b - 0.5 * (b1m4 - b2m5);
  2372. ap60 = S60 * ( a2p5 - a1p4);
  2373. bp60 = S60 * ( b2p5 - b1p4);
  2374. am60 = S60 * (-a2m5 - a1m4);
  2375. bm60 = S60 * (-b2m5 - b1m4);
  2376. c[j0+j] = a[i0+i] + ab3a + a1p4 + a2p5;
  2377. d[j0+j] = b[i0+i] + ab3b + b1p4 + b2p5;
  2378. c[j1+j] = am05 - bm60;
  2379. d[j1+j] = am60 - bm05;
  2380. c[j2+j] = ap05 - bp60;
  2381. d[j2+j] = ap60 + bp05;
  2382. c[j3+j] = a[i0+i] - ab3a - a1m4 + a2m5;
  2383. d[j3+j] =-b[i0+i] + ab3b + b1m4 - b2m5;
  2384. c[j4+j] = ap05 + bp60;
  2385. d[j4+j] = ap60 - bp05;
  2386. c[j5+j] = am05 + bm60;
  2387. d[j5+j] = am60 + bm05;
  2388. ENDL
  2389. j0 += jink;
  2390. j1 += jink;
  2391. j2 += jink;
  2392. j3 -= jink;
  2393. j4 -= jink;
  2394. j5 -= jink;
  2395. ibase += jump;
  2396. }
  2397. if (j2 > j3) return 0;
  2398. }
  2399. jbase = 0;
  2400. LOOP
  2401. a1p5 = a[i1+i] + a[i5+i];
  2402. a1m5 = a[i1+i] - a[i5+i];
  2403. a2p4 = a[i2+i] + a[i4+i];
  2404. a2m4 = a[i2+i] - a[i4+i];
  2405. c[j0+j] = a[i0+i] + 0.5 * a2m4 + S60 * a1m5;
  2406. d[j0+j] =-a[i3+i] - 0.5 * a1p5 - S60 * a2p4;
  2407. c[j1+j] = a[i0+i] - a2m4;
  2408. d[j1+j] = a[i3+i] - a1p5;
  2409. c[j2+j] = a[i0+i] + 0.5 * a2m4 - S60 * a1m5;
  2410. d[j2+j] =-a[i3+i] - 0.5 * a1p5 + S60 * a2p4;
  2411. ENDL
  2412. } else {
  2413. z = 1.0 / n;
  2414. y = S60 / n;
  2415. LOOP
  2416. a0p3 = a[i0+i] + a[i3+i];
  2417. a0m3 = a[i0+i] - a[i3+i];
  2418. a1p4 = a[i1+i] + a[i4+i];
  2419. a1m4 = a[i1+i] - a[i4+i];
  2420. a2p5 = a[i2+i] + a[i5+i];
  2421. a2m5 = a[i2+i] - a[i5+i];
  2422. c[j0+j] = z * (a0p3 + a1p4 + a2p5);
  2423. c[j3+j] = z * (a0m3 + a2m5 - a1m4);
  2424. c[j1+j] = z * (a0m3 - 0.5 * (a2m5 - a1m4));
  2425. c[j2+j] = z * (a0p3 - 0.5 * (a1p4 + a2p5));
  2426. d[j1+j] = y * (-a2m5 - a1m4);
  2427. d[j2+j] = y * ( a2p5 - a1p4);
  2428. ENDL
  2429. }
  2430. return 0;
  2431. }
  2432. case 8: {
  2433. double a0p4,a1p5,a2p6,a3p7;
  2434. double a0m4,a1m5,a2m6,a3m7;
  2435. if (la != m) return 3;
  2436. i0 = 0;
  2437. i1 = i0 + iink;
  2438. i2 = i1 + iink;
  2439. i3 = i2 + iink;
  2440. i4 = i3 + iink;
  2441. i5 = i4 + iink;
  2442. i6 = i5 + iink;
  2443. i7 = i6 + iink;
  2444. j0 = 0;
  2445. j1 = j0 + jink;
  2446. j2 = j1 + jink;
  2447. j3 = j2 + jink;
  2448. j4 = j3 + jink;
  2449. j5 = j4 + jink;
  2450. j6 = j5 + jink;
  2451. j7 = j6 + jink;
  2452. z = 1.0 / n;
  2453. y = SQ2 / n;
  2454. LOOP
  2455. a0p4 = a[i0+i] + a[i4+i];
  2456. a0m4 = a[i0+i] - a[i4+i];
  2457. a1p5 = a[i1+i] + a[i5+i];
  2458. a1m5 = a[i1+i] - a[i5+i];
  2459. a2p6 = a[i2+i] + a[i6+i];
  2460. a2m6 = a[i2+i] - a[i6+i];
  2461. a3p7 = a[i3+i] + a[i7+i];
  2462. a3m7 = a[i3+i] - a[i7+i];
  2463. c[j0+j] = z * (a0p4 + a1p5 + a2p6 + a3p7);
  2464. c[j7+j] = z * (a0p4 - a1p5 + a2p6 - a3p7);
  2465. c[j3+j] = z * (a0p4 - a2p6);
  2466. c[j4+j] = z * (a3p7 - a1p5);
  2467. c[j1+j] = z * a0m4 + y * (a1m5 - a3m7);
  2468. c[j5+j] = z * a0m4 - y * (a1m5 - a3m7);
  2469. c[j2+j] =-z * a2m6 - y * (a1m5 + a3m7);
  2470. c[j6+j] = z * a2m6 - y * (a1m5 + a3m7);
  2471. ENDL
  2472. }
  2473. }
  2474. return 0;
  2475. }
  2476. void fc2gp(double *fc, double *gp, int Lat, int Lon, int Lev, int Fou)
  2477. {
  2478. int Lot;
  2479. int fou;
  2480. int ia;
  2481. int ifac;
  2482. int j;
  2483. int jump;
  2484. int k;
  2485. int la;
  2486. int lat;
  2487. int lev;
  2488. int lon;
  2489. int nfax;
  2490. int rix;
  2491. int wix;
  2492. double *wpt;
  2493. /* fc2gp performs fourier to gridpoint transforms using */
  2494. /* multiple fast fourier transform of length Lon */
  2495. /* */
  2496. /* fc - real array of fourier coefficients fc[Lev][Fou][Lat] */
  2497. /* gp - real array of gridpoints gp[Lev][Lat][Lon] */
  2498. /* Lat - Number of latitudes */
  2499. /* Lon - Number of longitudes */
  2500. /* Lev - Number of levels */
  2501. /* Fou - Number of fourier coefficients on 1 latitude */
  2502. /* x(j) = sum(k=0,...,n-1)(c(k)*exp(2*i*j*k*pi/Lon)) */
  2503. /* where c(k) = a(k) + i*b(k) and c(n-k) = a(k)-i*b(k) */
  2504. jump = (Lon + 2) | 1;
  2505. Lot = Lev * Lat;
  2506. nfax = ifax[0];
  2507. for (lev = 0; lev < Lev; ++lev)
  2508. {
  2509. for (lat = 0; lat < Lat; ++lat)
  2510. {
  2511. wix = jump * (lat + lev * Lat);
  2512. rix = lat + lev * Lat * Fou;
  2513. for (fou = 0 ; fou < Fou && fou < jump ; ++fou)
  2514. wfc[wix + fou] = fc[rix + fou * Lat];
  2515. for (fou = Fou; fou < jump; ++fou)
  2516. wfc[wix + fou] = 0.0;
  2517. wfc[wix+1] = 0.5 * wfc[wix];
  2518. }
  2519. }
  2520. ia = 1;
  2521. la = 1;
  2522. for (k = 0; k < nfax; ++k) {
  2523. ifac = ifax[k+1];
  2524. if (k&1) rpassc(wgp,wgp+la,wfc+ia,wfc+ia+ifac*la,
  2525. jump,jump,Lot,Lon,ifac,la);
  2526. else rpassc(wfc+ia,wfc+ia+la,wgp,wgp+ifac*la,
  2527. jump,jump,Lot,Lon,ifac,la);
  2528. la *= ifac;
  2529. ia = 0;
  2530. }
  2531. if (nfax & 1) wpt = wgp;
  2532. else wpt = wfc;
  2533. for (j = 0; j < Lot ; ++j)
  2534. for (lon = 0; lon < Lon; ++lon)
  2535. gp[lon + j * Lon] = wpt[lon + j * jump];
  2536. }
  2537. void gp2fc(double *gp, double *fc, int Lat, int Lon, int Lev, int Fou)
  2538. {
  2539. int Lot;
  2540. int fou;
  2541. int ia;
  2542. int ifac;
  2543. int jump;
  2544. int k;
  2545. int la;
  2546. int lat;
  2547. int lev;
  2548. int lon;
  2549. int lot;
  2550. int nfax;
  2551. int rix;
  2552. int wix;
  2553. double *wpt;
  2554. /* gp2fc performs gridpoint to fourier transforms using */
  2555. /* multiple fast fourier transform of length Lon */
  2556. /* */
  2557. /* fc - real array of fourier coefficients fc[Lev][Fou][Lat] */
  2558. /* gp - real array of gridpoints gp[Lev][Lat][Lon] */
  2559. /* Lat - Number of latitudes */
  2560. /* Lon - Number of longitudes */
  2561. /* Lev - Number of levels */
  2562. /* Fou - Number of fourier coefficients on 1 latitude */
  2563. /* a(k) = (1/n) * sum(j=0,...,n-1)(x(j) * cos(2*j*k*pi/n)) */
  2564. /* b(k) = -(1/n) * sum(j=0,...,n-1)(x(j) * sin(2*j*k*pi/n)) */
  2565. if (!gp) Abort("gp2fc called with NULL pointer for gp");
  2566. if (!fc) Abort("gp2fc called with NULL pointer for fc");
  2567. jump = (Lon + 2) | 1;
  2568. Lot = Lev * Lat;
  2569. nfax = ifax[0];
  2570. rix = 0;
  2571. wix = 0;
  2572. for (lot = 0; lot < Lot; ++lot) {
  2573. for (lon = 0; lon < Lon; ++lon) wgp[wix+lon] = gp[rix+lon];
  2574. wgp[wix+Lon ] = 0.0;
  2575. wgp[wix+Lon+1] = 0.0;
  2576. rix += Lon;
  2577. wix += jump;
  2578. }
  2579. ia = 0;
  2580. la = Lon;
  2581. for (k = 0; k < nfax; ++k) {
  2582. ifac = ifax[nfax-k];
  2583. la /= ifac;
  2584. if (k & 1) qpassc(wfc,wfc+ifac*la,wgp+ia,wgp+ia+la,
  2585. jump,jump,Lot,Lon,ifac,la);
  2586. else qpassc(wgp+ia,wgp+ia+ifac*la,wfc,wfc+la,
  2587. jump,jump,Lot,Lon,ifac,la);
  2588. ia = 1;
  2589. }
  2590. if (nfax & 1) wpt = wfc;
  2591. else wpt = wgp+1;
  2592. for (lev = 0; lev < Lev; ++lev) {
  2593. for (lat = 0; lat < Lat; ++lat) {
  2594. rix = jump * (lat + lev * Lat);
  2595. wix = lat + lev * Lat * Fou;
  2596. fc[wix ] = wpt[rix];
  2597. fc[wix+Lat] = 0.0;
  2598. for (fou = 2 ; fou < Fou ; ++fou)
  2599. fc[wix + fou * Lat] = wpt[rix + fou - 1];
  2600. }
  2601. }
  2602. }
  2603. inline void SwapIEEE(char W[4])
  2604. {
  2605. char B;
  2606. B = W[0]; W[0] = W[3]; W[3] = B;
  2607. B = W[1]; W[1] = W[2]; W[2] = B;
  2608. }
  2609. inline void SwapIEEE64(char W[8])
  2610. {
  2611. char B;
  2612. B = W[0]; W[0] = W[3]; W[3] = B;
  2613. B = W[1]; W[1] = W[2]; W[2] = B;
  2614. B = W[4]; W[4] = W[7]; W[7] = B;
  2615. B = W[5]; W[5] = W[6]; W[6] = B;
  2616. }
  2617. int check_fcw(int fcws, int fcwe)
  2618. {
  2619. if (fcwe != fcws)
  2620. {
  2621. printf("\n*************** ERROR reading input file **************\n");
  2622. printf("The FORTRAN control words (FCW) of a record don't match\n");
  2623. printf("FCW before record = %d\n",fcws);
  2624. printf("FCW after record = %d\n",fcwe);
  2625. printf("File position: %ld\n",ftell(fpi));
  2626. printf("Possible causes are:\n");
  2627. printf("1) Model crashed leaving an incomplete output file\n");
  2628. printf("2) Corrupt data file (cache or disk problems)\n");
  2629. return 1;
  2630. }
  2631. return 0;
  2632. }
  2633. /* =============================== */
  2634. /* Read IEEE 32 bit data from file */
  2635. /* =============================== */
  2636. inline int ReadINT(void)
  2637. {
  2638. int k;
  2639. fread(&k,sizeof(k),1,fpi);
  2640. if (Endian) SwapIEEE((char *)&k);
  2641. return k;
  2642. }
  2643. inline LONG ReadLONG(void)
  2644. {
  2645. LONG l;
  2646. fread(&l,sizeof(l),1,fpi);
  2647. if (Endian) SwapIEEE64((char *)&l);
  2648. return l;
  2649. }
  2650. inline int ReadFCW(void)
  2651. {
  2652. int k;
  2653. LONG l;
  2654. if (LongFCW)
  2655. {
  2656. fread(&l,sizeof(l),1,fpi);
  2657. if (Endian) SwapIEEE64((char *)&l);
  2658. k = (int)l;
  2659. }
  2660. else
  2661. {
  2662. fread(&k,sizeof(k),1,fpi);
  2663. if (Endian) SwapIEEE((char *)&k);
  2664. }
  2665. return k;
  2666. }
  2667. inline float ReadFLOAT(void)
  2668. {
  2669. int i;
  2670. float f;
  2671. i = fread(&f,sizeof(f),1,fpi);
  2672. if (i != 1) Abort("Unexpected EOF in ReadFLOAT");
  2673. if (Endian) SwapIEEE((char *)&f);
  2674. return f;
  2675. }
  2676. inline double ReadDOUBLE(void)
  2677. {
  2678. int i;
  2679. double f;
  2680. i = fread(&f,sizeof(f),1,fpi);
  2681. if (i != 1) Abort("Unexpected EOF in ReadDOUBLE");
  2682. if (Endian) SwapIEEE64((char *)&f);
  2683. return f;
  2684. }
  2685. inline int ReadINTRecord(void)
  2686. {
  2687. int k,b,e;
  2688. b = ReadFCW();
  2689. fread(&k,sizeof(k),1,fpi); /* IEEE 32-bit integer */
  2690. e = ReadFCW();
  2691. if (check_fcw(b,e)) Abort("record control word mismatch in ReadINTRecord");
  2692. if (Endian) SwapIEEE((char *)&k);
  2693. return k;
  2694. }
  2695. inline int Skip_FORTRAN_Record(void)
  2696. {
  2697. int fcws,fcwe;
  2698. fcws = ReadFCW();
  2699. if (feof(fpi)) return 0;
  2700. fseek(fpi,fcws,SEEK_CUR);
  2701. fcwe = ReadFCW();
  2702. if (check_fcw(fcws,fcwe))
  2703. Abort("record control word mismatch in Skip_FORTRAN_Record");
  2704. return fcws;
  2705. }
  2706. inline void Swap_FORTRAN_Record(char *c, int n)
  2707. {
  2708. char b;
  2709. int i;
  2710. for (i=0 ; i < n ; i+=4)
  2711. {
  2712. b = c[i ]; c[i ] = c[i+3]; c[i+3] = b;
  2713. b = c[i+1]; c[i+1] = c[i+2]; c[i+2] = b;
  2714. }
  2715. }
  2716. inline void Swap_FORTRAN_Double(char *c, int n)
  2717. {
  2718. char b;
  2719. int i;
  2720. for (i=0 ; i < n ; i+=8)
  2721. {
  2722. b = c[i ]; c[i ] = c[i+7]; c[i+7] = b;
  2723. b = c[i+1]; c[i+1] = c[i+6]; c[i+6] = b;
  2724. b = c[i+2]; c[i+2] = c[i+5]; c[i+5] = b;
  2725. b = c[i+3]; c[i+3] = c[i+4]; c[i+4] = b;
  2726. }
  2727. }
  2728. inline int Read_FORTRAN_Record(void)
  2729. {
  2730. int fcws,fcwe;
  2731. fcws = ReadFCW();
  2732. if (feof(fpi)) return 0;
  2733. fread(Record_char,1,fcws,fpi);
  2734. fcwe = ReadFCW();
  2735. if (check_fcw(fcws,fcwe)) Abort("record control word mismatch in Read_FORTRAN_Record");
  2736. if (Endian) Swap_FORTRAN_Record(Record_char,fcws);
  2737. return fcws;
  2738. }
  2739. inline int Read_FORTRAN_Double_Record(void)
  2740. {
  2741. int fcws,fcwe;
  2742. fcws = ReadFCW();
  2743. if (feof(fpi)) return 0;
  2744. fread(Record_char,1,fcws,fpi);
  2745. fcwe = ReadFCW();
  2746. if (check_fcw(fcws,fcwe)) Abort("record control word mismatch in Read_FORTRAN_Double_Record");
  2747. if (Endian) Swap_FORTRAN_Double(Record_char,fcws);
  2748. return fcws;
  2749. }
  2750. int ReadHeaderRecord(void)
  2751. {
  2752. int h,i,fcws,fcwe;
  2753. fcws = ReadFCW();
  2754. if (feof(fpi)) return 1;
  2755. if (fcws == 8) /* Skip PUMA header */
  2756. {
  2757. if (Debug)
  2758. {
  2759. printf("Skipping %d header words\n",HeaderWords);
  2760. for (i=0 ; i < HeaderWords ; ++i)
  2761. {
  2762. h = ReadINT();
  2763. printf("HW[%2d] = %8x %d\n",i,h,h);
  2764. }
  2765. }
  2766. else
  2767. for (i=0 ; i < HeaderWords ; ++i) ReadINT();
  2768. fcws = ReadFCW();
  2769. if (feof(fpi))
  2770. {
  2771. printf("\n#### Empty data file #####\n");
  2772. printf("Mark [Write Ouput] in MoSt\n");
  2773. printf("or set NOUTPUT=1 in file <puma_namelist>\n");
  2774. Abort("Empty data file");
  2775. }
  2776. }
  2777. if (fcws != HeadSize)
  2778. {
  2779. printf("FCW = %d (should be %d)\n",fcws,HeadSize);
  2780. Abort("Wrong FCW found in ReadHeaderRecord");
  2781. }
  2782. for (i=0 ; i < 8 ; ++i)
  2783. {
  2784. if (HeadSize == 32) HeadIn[i] = ReadINT();
  2785. else HeadIn[i] = ReadLONG();
  2786. }
  2787. fcwe = ReadFCW();
  2788. if (check_fcw(fcws,fcwe)) Abort("FCW mismatch in ReadHeaderRecord");
  2789. return 0;
  2790. }
  2791. void DecodePumaHeader(void)
  2792. {
  2793. PumaCode = HeadIn[0];
  2794. PumaLevel = HeadIn[1];
  2795. NewDate.tm_year = HeadIn[2] / 10000;
  2796. NewDate.tm_mon = HeadIn[2] / 100 % 100;
  2797. NewDate.tm_mday = HeadIn[2] % 100;
  2798. NewDate.tm_hour = HeadIn[3] / 100;
  2799. NewDate.tm_min = HeadIn[3] % 100;
  2800. if (DayDivisor > 1) NewMonth = (TermCount / DPM) % 12 + 1;
  2801. else NewMonth = NewDate.tm_mon;
  2802. if (HeadIn[4] * HeadIn[5] == DimSP) RepGrib = REP_SPECTRAL;
  2803. else RepGrib = REP_GAUSS;
  2804. if (PumaCode < 0 || PumaCode >= CODES)
  2805. {
  2806. printf("Illegal Code %d in header\n",PumaCode);
  2807. Abort("Code < 0 or Code > CODES found");
  2808. }
  2809. All[PumaCode].detected = TRUE;
  2810. }
  2811. // =============
  2812. // ReadPumaArray
  2813. // =============
  2814. void ReadPumaArray(double *Array)
  2815. {
  2816. int i,j,fcws;
  2817. double zfac;
  2818. double zmin;
  2819. if (RealSize == sizeof(float)) fcws = Read_FORTRAN_Record();
  2820. else fcws = Read_FORTRAN_Double_Record();
  2821. if (fcws == sizeof(float) * (Truncation + 2)) // Packed spectral data
  2822. {
  2823. for (i=0 ; i <= Truncation ; i++)
  2824. {
  2825. Array[2*i ] = Record_float[i];
  2826. Array[2*i+1] = 0.0; // Imaginary parts of zonal modes
  2827. }
  2828. zfac = 1.0 / Record_float[Truncation+1];
  2829. fcws = Read_FORTRAN_Record();
  2830. if (CoreBigEndian)
  2831. {
  2832. for (i=2*Truncation+2,j=0 ; i < DimSP ; ++i,++j)
  2833. {
  2834. Array[i] = (Record_short[j] - 32768) * zfac;
  2835. }
  2836. }
  2837. else
  2838. {
  2839. for (i=2*Truncation+2,j=0 ; i < DimSP ; i+=2,j+=2)
  2840. {
  2841. Array[i ] = (Record_short[j+1] - 32768) * zfac;
  2842. Array[i+1] = (Record_short[j ] - 32768) * zfac;
  2843. }
  2844. }
  2845. }
  2846. else if (fcws == sizeof(float) * DimSP) // Unpacked spectral float data
  2847. {
  2848. for (i=0 ; i < DimSP ; ++i) Array[i] = Record_float[i];
  2849. }
  2850. else if (fcws == sizeof(double) * DimSP) // Unpacked spectral double data
  2851. {
  2852. memcpy(Array,Record_double,fcws);
  2853. }
  2854. else if (fcws == sizeof(float) * DimGG) // Unpacked grid float data
  2855. {
  2856. for (i=0 ; i < DimGG ; ++i) Array[i] = Record_float[i];
  2857. }
  2858. else if (fcws == sizeof(double) * DimGG) // Unpacked grid double data
  2859. {
  2860. memcpy(Array,Record_double,fcws);
  2861. }
  2862. else if (fcws == 8) /* Packed grid data */
  2863. {
  2864. zmin = Record_float[0];
  2865. zfac = 1.0 / Record_float[1];
  2866. fcws = Read_FORTRAN_Record();
  2867. if (CoreBigEndian)
  2868. {
  2869. for (i=0 ; i < DimGG ; ++i)
  2870. {
  2871. Array[i] = Record_short[i] * zfac + zmin;
  2872. }
  2873. }
  2874. else
  2875. {
  2876. for (i=0 ; i < DimGG ; i+=2)
  2877. {
  2878. Array[i ] = Record_short[i+1] * zfac + zmin;
  2879. Array[i+1] = Record_short[i ] * zfac + zmin;
  2880. }
  2881. }
  2882. }
  2883. else Abort("fcws error in ReadPumaArray");
  2884. }
  2885. /* ============= */
  2886. /* SkipPumaArray */
  2887. /* ============= */
  2888. void SkipPumaArray(void)
  2889. {
  2890. int fcws;
  2891. fcws = Skip_FORTRAN_Record();
  2892. if (fcws == 8 || fcws == 4 * (Truncation + 2))
  2893. fcws = Skip_FORTRAN_Record();
  2894. }
  2895. /* ============================================= */
  2896. /* phcs - Compute values of Legendre polynomials */
  2897. /* and their meridional derivatives */
  2898. /* ============================================= */
  2899. void phcs(double *PNM, double *HNM, int Waves, double PMU,
  2900. double *ZTEMP1, double *ZTEMP2)
  2901. {
  2902. long TwoWaves;
  2903. long JK;
  2904. long JN;
  2905. long JM;
  2906. double JNmJK;
  2907. double ZCOS2;
  2908. double Lat;
  2909. double ZAN;
  2910. double ZSINPAR;
  2911. double ZCOSPAR;
  2912. double ZSQP;
  2913. double ZCOSFAK;
  2914. double ZSINFAK;
  2915. double ZQ;
  2916. double ZWM2;
  2917. double ZW;
  2918. double ZWQ;
  2919. double ZQ2M1;
  2920. double ZWM2Q2;
  2921. double Z2Q2;
  2922. double ZCNM;
  2923. double ZDNM;
  2924. double ZENM;
  2925. TwoWaves = Waves << 1;
  2926. ZCOS2 = sqrt(1.0 - PMU * PMU);
  2927. Lat = acos(PMU);
  2928. ZAN = 1.0;
  2929. ZTEMP1[0] = 0.5;
  2930. for (JN = 1; JN < TwoWaves; JN++) {
  2931. ZSQP = 1.0 / sqrt((double)(JN+JN*JN));
  2932. ZAN *= sqrt(1.0 - 1.0 / (4 * JN * JN));
  2933. ZCOSPAR = cos(Lat * JN);
  2934. ZSINPAR = sin(Lat * JN) * JN * ZSQP;
  2935. ZCOSFAK = 1.0;
  2936. for (JK = 2; JK < JN; JK += 2) {
  2937. JNmJK = JN - JK;
  2938. ZCOSFAK *= (JK-1) * (JN+JNmJK+2) / (JK * (JN+JNmJK+1));
  2939. ZSINFAK = ZCOSFAK * (JNmJK) * ZSQP;
  2940. ZCOSPAR += ZCOSFAK * cos(Lat * JNmJK);
  2941. ZSINPAR += ZSINFAK * sin(Lat * JNmJK);
  2942. }
  2943. /* Code for JK == JN */
  2944. if ((JN & 1) == 0) {
  2945. ZCOSFAK *= (double)((JN-1) * (JN+2)) / (double)(JN * (JN+1));
  2946. ZCOSPAR += ZCOSFAK * 0.5;
  2947. }
  2948. ZTEMP1[JN ] = ZAN * ZCOSPAR;
  2949. ZTEMP2[JN-1] = ZAN * ZSINPAR;
  2950. }
  2951. memcpy(PNM,ZTEMP1,Waves * sizeof(double));
  2952. PNM += Waves;
  2953. memcpy(PNM,ZTEMP2,Waves * sizeof(double));
  2954. PNM += Waves;
  2955. HNM[0] = 0.0;
  2956. for (JN = 1; JN < Waves; JN++) HNM[JN] =
  2957. JN * (PMU * ZTEMP1[JN] - sqrt((JN+JN+1.0) / (JN+JN-1.0)) * ZTEMP1[JN-1]);
  2958. HNM += Waves;
  2959. HNM[0] = PMU * ZTEMP2[0];
  2960. for (JN = 1; JN < Waves; JN++)
  2961. HNM[JN] = (JN+1) * PMU * ZTEMP2[JN]
  2962. - sqrt((double)((JN+JN+3) * ((JN+1) * (JN+1) - 1))
  2963. / (double)(JN+JN+1)) * ZTEMP2[JN-1];
  2964. HNM += Waves;
  2965. for (JM = 2; JM < Waves; JM++) {
  2966. PNM[0] = sqrt(1.0 + 1.0 / (JM+JM)) * ZCOS2 * ZTEMP2[0];
  2967. HNM[0] = JM * PMU * PNM[0];
  2968. for (JN = 1; JN < TwoWaves-JM; JN++) {
  2969. ZQ = JM + JM + JN - 1;
  2970. ZWM2 = ZQ+JN;
  2971. ZW = ZWM2+2;
  2972. ZWQ = ZW*ZQ;
  2973. ZQ2M1 = ZQ*ZQ-1.;
  2974. ZWM2Q2 = ZWM2*ZQ2M1;
  2975. Z2Q2 = ZQ2M1*2;
  2976. ZCNM = sqrt((ZWQ*(ZQ-2.))/(ZWM2Q2-Z2Q2));
  2977. ZDNM = sqrt((ZWQ*(JN+1.))/ZWM2Q2);
  2978. ZENM = sqrt(ZW * JN /((ZQ+1.0) * ZWM2));
  2979. PNM[JN] = ZCNM * ZTEMP1[JN] - PMU
  2980. * (ZDNM * ZTEMP1[JN+1] - ZENM * PNM[JN-1]);
  2981. HNM[JN] = (JM + JN) * PMU * PNM[JN]
  2982. - sqrt(ZW * JN * (ZQ+1) / ZWM2) * PNM[JN-1];
  2983. }
  2984. memcpy(ZTEMP1,ZTEMP2,TwoWaves * sizeof(double));
  2985. memcpy(ZTEMP2,PNM ,TwoWaves * sizeof(double));
  2986. PNM += Waves;
  2987. HNM += Waves;
  2988. }
  2989. }
  2990. void legini(void)
  2991. {
  2992. int jlat,jm,jn,jz;
  2993. int jsp,pdim,hdim;
  2994. double *hnm,*pnm,*ZTEMP1,*ZTEMP2,gmusq;
  2995. double znn1,zgmu;
  2996. char tb[COLS+2];
  2997. double poliv,pol2v,pliuv,plivv;
  2998. hdim = 2 * Waves * Waves;
  2999. if (PolyCreate) /* Generate filenames for polynomials */
  3000. {
  3001. sprintf(polin,"b6poli.T%d",Truncation);
  3002. sprintf(pol2n,"b6pol2.T%d",Truncation);
  3003. sprintf(pliun,"b6pliu.T%d",Truncation);
  3004. sprintf(plivn,"b6pliv.T%d",Truncation);
  3005. }
  3006. else if (PolyDisk) /* Generate filenames for polynomials */
  3007. {
  3008. sprintf(polin,"/comm/T1365/b6poli.t%d",Truncation);
  3009. sprintf(pol2n,"/comm/T1365/b6pol2.t%d",Truncation);
  3010. sprintf(pliun,"/comm/T1365/b6pliu.t%d",Truncation);
  3011. sprintf(plivn,"/comm/T1365/b6pliv.t%d",Truncation);
  3012. polif = fopen(polin,"r");
  3013. pol2f = fopen(pol2n,"r");
  3014. pliuf = fopen(pliun,"r");
  3015. plivf = fopen(plivn,"r");
  3016. if (polif && pol2f && pliuf && plivf)
  3017. sprintf(tb,"Legendre Polynomials read from disk");
  3018. else
  3019. {
  3020. sprintf(tb,"Legendre Polynomials calculated");
  3021. PolyDisk = 0;
  3022. }
  3023. CenterText(tb);
  3024. }
  3025. if (PolyDisk) pdim = Lats;
  3026. else pdim = Lats * DimSP_half;
  3027. poli = new double[pdim];
  3028. pol2 = new double[pdim];
  3029. pliu = new double[pdim];
  3030. pliv = new double[pdim];
  3031. pnm = new double[hdim];
  3032. hnm = new double[hdim];
  3033. ZTEMP1 = new double[Fouriers];
  3034. ZTEMP2 = new double[Fouriers];
  3035. // if gridtype for output is not selected, choose Gauss grid
  3036. // for matching resolution and regular grid else
  3037. if (GaussGrid < 0) GaussGrid = (Lats == Gats && Lons == Gons);
  3038. Gaulat = new GauLat(Gats,"Gaulat"); // Gaussian latitudes of input grid
  3039. Outlon = new RegLon(Lons,"Outlon"); // Regular longitudes of output grid
  3040. if (GaussGrid) Outlat = new GauLat(Lats,"Outlat");
  3041. else Outlat = new RegLat(Lats,"Outlat");
  3042. if (Debug)
  3043. {
  3044. Gaulat->PrintArray();
  3045. if (Lats != Gats || !GaussGrid) Outlat->PrintArray();
  3046. Outlon->PrintArray();
  3047. }
  3048. if (PolyCreate)
  3049. {
  3050. polif = fopen(polin,"w");
  3051. pol2f = fopen(pol2n,"w");
  3052. pliuf = fopen(pliun,"w");
  3053. plivf = fopen(plivn,"w");
  3054. for (jlat = 0 ; jlat < Lats ; ++jlat)
  3055. {
  3056. gmusq = 1.0 - Outlat->gmu[jlat] * Outlat->gmu[jlat];
  3057. zgmu = sqrt(gmusq);
  3058. phcs(pnm,hnm,Waves,Outlat->gmu[jlat],ZTEMP1,ZTEMP2);
  3059. for (jm = 0; jm < Waves; jm++)
  3060. {
  3061. for (jn = 0; jn < Waves - jm ; jn++)
  3062. {
  3063. jz = jm+jn;
  3064. znn1 = 0.0;
  3065. if (jz > 0) znn1 = 1.0 / (jz * (jz+1));
  3066. poliv = pnm[jm*Waves+jn] * 2.0;
  3067. fwrite(&poliv,sizeof(double),1,polif);
  3068. pol2v = hnm[jm*Waves+jn] / PlanetRadius;
  3069. fwrite(&pol2v,sizeof(double),1,pol2f);
  3070. pliuv = pnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 * jm / zgmu;
  3071. fwrite(&pliuv,sizeof(double),1,pliuf);
  3072. plivv = hnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 / zgmu;
  3073. fwrite(&plivv,sizeof(double),1,plivf);
  3074. }
  3075. }
  3076. }
  3077. }
  3078. else if (PolyDisk)
  3079. {
  3080. for (jlat = 0 ; jlat < Lats ; ++jlat)
  3081. {
  3082. gmusq = 1.0 - Outlat->gmu[jlat] * Outlat->gmu[jlat];
  3083. CosPhi[jlat] = sqrt(gmusq);
  3084. RevCosPhi[jlat] = 1.0 / CosPhi[jlat];
  3085. DerivationFactor[jlat] = RevCosPhi[jlat] / PlanetRadius;
  3086. }
  3087. }
  3088. else /* Normal computation of polynomials */
  3089. {
  3090. for (jlat = 0 ; jlat < Lats ; ++jlat)
  3091. {
  3092. gmusq = 1.0 - Outlat->gmu[jlat] * Outlat->gmu[jlat];
  3093. CosPhi[jlat] = sqrt(gmusq);
  3094. RevCosPhi[jlat] = 1.0 / CosPhi[jlat];
  3095. DerivationFactor[jlat] = RevCosPhi[jlat] / PlanetRadius;
  3096. phcs(pnm,hnm,Waves,Outlat->gmu[jlat],ZTEMP1,ZTEMP2);
  3097. jsp = jlat;
  3098. for (jm = 0; jm < Waves; jm++)
  3099. {
  3100. for (jn = 0; jn < Waves - jm ; jn++)
  3101. {
  3102. jz = jm+jn;
  3103. znn1 = 0.0;
  3104. if (jz > 0) znn1 = 1.0 / (jz * (jz+1));
  3105. poli[jsp] = pnm[jm*Waves+jn] * 2.0;
  3106. pol2[jsp] = hnm[jm*Waves+jn] / PlanetRadius;
  3107. pliu[jsp] = pnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 * jm / sqrt(gmusq);
  3108. pliv[jsp] = hnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 / sqrt(gmusq);
  3109. jsp += Lats;
  3110. }
  3111. }
  3112. }
  3113. }
  3114. delete [] pnm;
  3115. delete [] hnm;
  3116. delete [] ZTEMP1;
  3117. delete [] ZTEMP2;
  3118. }
  3119. void spvfc(double *sd, double *sz, double *fu, double *fv, int klev,int nlat,int nfc,int nt)
  3120. {
  3121. int lev,jmm,jfc,lat;
  3122. double sdr,sdi,szr,szi;
  3123. double *fur,*fui,*fvr,*fvi;
  3124. double *poa,*pob;
  3125. DoubleZero(fu,klev*nlat*nfc);
  3126. DoubleZero(fv,klev*nlat*nfc);
  3127. for (lev = 0; lev < klev; lev++)
  3128. {
  3129. if (PolyDisk)
  3130. {
  3131. rewind(pliuf);
  3132. rewind(plivf);
  3133. }
  3134. poa = pliu;
  3135. pob = pliv;
  3136. for (jmm = 0; jmm <= nt; jmm++)
  3137. {
  3138. for (jfc = jmm; jfc <= nt; jfc++)
  3139. {
  3140. sdr = *sd++;
  3141. sdi = *sd++;
  3142. szr = *sz++;
  3143. szi = *sz++;
  3144. fur = fu ;
  3145. fui = fu + nlat;
  3146. fvr = fv ;
  3147. fvi = fv + nlat;
  3148. if (PolyDisk)
  3149. {
  3150. fread(poa=pliu,sizeof(double),Lats,pliuf);
  3151. fread(pob=pliv,sizeof(double),Lats,plivf);
  3152. }
  3153. for (lat = 0; lat < nlat; lat++)
  3154. {
  3155. *fur += -*pob * szr + *poa * sdi;
  3156. *fui += -*pob * szi - *poa * sdr;
  3157. *fvr += *poa * szi + *pob * sdr;
  3158. *fvi += -*poa * szr + *pob * sdi;
  3159. fur++;
  3160. fui++;
  3161. fvr++;
  3162. fvi++;
  3163. poa++;
  3164. pob++;
  3165. }
  3166. }
  3167. fu += 2 * nlat;
  3168. fv += 2 * nlat;
  3169. }
  3170. }
  3171. }
  3172. // ========================================
  3173. // sp2fci - Inverse Legendre Transformation
  3174. // ========================================
  3175. void sp2fci(double *sa,double *fa,int klev)
  3176. {
  3177. int lev,m,n;
  3178. double sar,sai;
  3179. double *Far,*Fai,*pol;
  3180. DoubleZero(fa,klev*DimFC);
  3181. for (lev = 0; lev < klev; ++lev)
  3182. {
  3183. if (PolyDisk) rewind(polif);
  3184. pol = poli;
  3185. for (n = 0; n <= Truncation; ++n)
  3186. {
  3187. if (PolyDisk) fread(pol=poli,sizeof(double),Lats,polif);
  3188. sar = *sa;
  3189. sa += 2;
  3190. for (Far=fa; Far < fa+Lats;++Far,++pol)
  3191. {
  3192. *Far += *pol * sar;
  3193. }
  3194. }
  3195. fa += 2 * Lats;
  3196. for (m = 1; m <= Truncation; ++m)
  3197. {
  3198. for (n = m; n <= Truncation; ++n)
  3199. {
  3200. if (PolyDisk) fread(pol=poli,sizeof(double),Lats,polif);
  3201. sar = *sa++ ;
  3202. sai = *sa++ ;
  3203. for (Far=fa,Fai=fa+Lats; Far<fa+Lats; ++Far,++Fai,++pol)
  3204. {
  3205. *Far += *pol * sar;
  3206. *Fai += *pol * sai;
  3207. }
  3208. }
  3209. fa += 2 * Lats;
  3210. }
  3211. }
  3212. }
  3213. void sp2fcd(double *sa,double *fa,int klev,int nlat,int nfc,int nt)
  3214. {
  3215. int lev,jmm,jfc,lat;
  3216. double sar,sai;
  3217. double *Far,*fai,*pol;
  3218. double zpo;
  3219. DoubleZero(fa,klev*nlat*nfc);
  3220. for (lev = 0; lev < klev; lev++)
  3221. {
  3222. pol = pol2;
  3223. if (PolyDisk) rewind(pol2f);
  3224. for (jmm = 0; jmm <= nt; jmm++)
  3225. {
  3226. for (jfc = jmm; jfc <= nt; jfc++)
  3227. {
  3228. sar = *sa++ ;
  3229. sai = *sa++ ;
  3230. Far = fa ;
  3231. fai = fa + nlat ;
  3232. if (PolyDisk) fread(pol=pol2,sizeof(double),Lats,pol2f);
  3233. for (lat = 0; lat < nlat; lat++)
  3234. {
  3235. zpo = -2.0 * *pol * RevCosPhi[lat];
  3236. *Far += zpo * sar;
  3237. *fai += zpo * sai;
  3238. Far++;
  3239. fai++;
  3240. pol++;
  3241. }
  3242. }
  3243. fa += 2 * nlat;
  3244. }
  3245. }
  3246. }
  3247. void fc2sp(double *fa, double *sa, int klev, int nlat, int nt)
  3248. {
  3249. int lev,jmm,jfc,lat;
  3250. double sar,sai,*Far,*fai,*pol;
  3251. double zpo;
  3252. for (lev = 0; lev < klev; lev++)
  3253. {
  3254. pol = poli;
  3255. if (PolyDisk) rewind(polif);
  3256. for (jmm = 0; jmm <= nt; jmm++)
  3257. {
  3258. for (jfc = jmm; jfc <= nt; jfc++)
  3259. {
  3260. Far = fa ;
  3261. fai = fa + nlat ;
  3262. sar = 0.0 ;
  3263. sai = 0.0 ;
  3264. if (PolyDisk) fread(pol=poli,sizeof(double),Lats,polif);
  3265. for (lat = 0; lat < nlat; lat++)
  3266. {
  3267. zpo = *pol * 0.5 * Outlat->gwt[lat];
  3268. sar += zpo * *Far;
  3269. sai += zpo * *fai;
  3270. Far++;
  3271. fai++;
  3272. pol++;
  3273. }
  3274. *sa++ = sar;
  3275. *sa++ = sai;
  3276. }
  3277. fa += 2 * nlat;
  3278. }
  3279. }
  3280. }
  3281. void OMEGA(void)
  3282. {
  3283. int i,j;
  3284. double DeltaHybrid;
  3285. double Cterm;
  3286. double Pterm;
  3287. double *omega = &Omega->hgp[0];
  3288. double *diver = &Divergence->hgp[0];
  3289. double *halfp = &HalfPress->hgp[0];
  3290. double *fullp = &FullPress->hgp[0];
  3291. double *uwind = &u_wind->hgp[0];
  3292. double *vwind = &v_wind->hgp[0];
  3293. /* Compute half level part of vertical velocity */
  3294. for (i = 0; i < DimGP ; i++) omega[i] = 0.0;
  3295. for (j = 0; j < SigLevs; j++) {
  3296. DeltaHybrid = vct[SigLevs+j+2] - vct[SigLevs+j+1];
  3297. for (i = 0; i < DimGP; i++) {
  3298. omega[DimGP] = *omega
  3299. - *diver * (halfp[DimGP] - *halfp) - DeltaHybrid
  3300. * (*uwind * dpsdx->hgp[i]
  3301. + *vwind * dpsdy->hgp[i]);
  3302. omega++;
  3303. halfp++;
  3304. diver++;
  3305. uwind++;
  3306. vwind++;
  3307. }
  3308. }
  3309. /* interpolate to full levels */
  3310. omega = &Omega->hgp[0];
  3311. for (i = 0; i < Dim3GP; i++)
  3312. omega[i] = 0.5 * (omega[i] + omega[i+DimGP]);
  3313. /* compute full level part of vertical velocity */
  3314. omega = &Omega->hgp[0];
  3315. halfp = &HalfPress->hgp[0];
  3316. fullp = &FullPress->hgp[0];
  3317. uwind = &u_wind->hgp[0];
  3318. vwind = &v_wind->hgp[0];
  3319. for (j = 0; j < SigLevs; j++) {
  3320. DeltaHybrid = vct[SigLevs+j+2] - vct[SigLevs+j+1];
  3321. if (DeltaHybrid) {
  3322. Cterm = vct[j+1] * vct[SigLevs+j+1] - vct[j] * vct[SigLevs+j+2];
  3323. for (i = 0; i < DimGP; i++) {
  3324. if (Cterm != 0.0) Pterm = Cterm /
  3325. (halfp[DimGP] - *halfp) * log(halfp[DimGP] / *halfp);
  3326. else Pterm = 0.0;
  3327. *omega += *fullp *
  3328. (*uwind * dpsdx->hgp[i] + *vwind * dpsdy->hgp[i])
  3329. / (halfp[DimGP] - *halfp) * (DeltaHybrid + Pterm);
  3330. omega++;
  3331. halfp++;
  3332. fullp++;
  3333. uwind++;
  3334. vwind++;
  3335. }
  3336. }
  3337. else {
  3338. omega += DimGP;
  3339. halfp += DimGP;
  3340. fullp += DimGP;
  3341. uwind += DimGP;
  3342. vwind += DimGP;
  3343. }
  3344. }
  3345. }
  3346. void Omega_w(double w[], double om[], double T[], double P[])
  3347. {
  3348. int i;
  3349. for (i=0 ; i < Dim3GP ; ++i)
  3350. {
  3351. w[i] = -om[i] * RD * T[i] / (Grav * P[i]);
  3352. }
  3353. }
  3354. void Extrap(double *slp, double *aph, double *apf,
  3355. double *Geopotential, double *t, int nhor)
  3356. {
  3357. double zrg = 1.0 / Grav;
  3358. double alpha,tstar,tmsl,ZPRT,ZPRTAL;
  3359. int j;
  3360. for (j = 0; j < nhor; ++j) {
  3361. if (Geopotential[j] < 0.0001 && Geopotential[j] > -0.0001) slp[j] = aph[j];
  3362. else {
  3363. alpha = RD * RLAPSE * zrg;
  3364. tstar = (1.0 + alpha * (aph[j]/apf[j] - 1.0)) * t[j];
  3365. if (tstar < 255.0) tstar = 0.5 * (255.0 + tstar);
  3366. tmsl = tstar + RLAPSE * zrg * Geopotential[j];
  3367. if (tmsl > 290.5 && tstar > 290.5) {
  3368. tstar = 0.5 * (290.5 + tstar);
  3369. tmsl = tstar;
  3370. }
  3371. if (tmsl-tstar < 0.000001 && tstar-tmsl < 0.000001) alpha = 0.0;
  3372. else if (Geopotential[j] > 0.0001 || Geopotential[j] < -0.0001)
  3373. alpha = RD * (tmsl-tstar) / Geopotential[j];
  3374. ZPRT = Geopotential[j] / (RD * tstar);
  3375. ZPRTAL = ZPRT * alpha;
  3376. slp[j] = aph[j] * exp(ZPRT*(1.0-ZPRTAL*(0.5-ZPRTAL/3.0)));
  3377. }
  3378. }
  3379. }
  3380. double ExtraT(double PRES, double APH, double APF, double GEOS, double T)
  3381. {
  3382. double zrg = 1.0 / Grav;
  3383. double tstar,ztsz,Z1,ZTMSL,ZALPH,PEVAL,ZHTS,ZALP;
  3384. tstar = (1.0 + RLAPSE * RD * zrg * (APH/APF - 1.0)) * T;
  3385. ztsz = tstar;
  3386. Z1 = tstar + RLAPSE * zrg * GEOS;
  3387. if (tstar < 255.0) tstar = 0.5 * (255.0 + tstar);
  3388. ZTMSL = tstar + RLAPSE * zrg * GEOS;
  3389. if (ZTMSL > 290.5 && tstar > 290.5)
  3390. {
  3391. tstar = 0.5 * (290.5 + tstar);
  3392. ZTMSL = tstar;
  3393. }
  3394. if (ZTMSL > 290.5 && tstar <= 290.5) ZTMSL=290.5;
  3395. ZALPH=RD*RLAPSE*zrg;
  3396. if ( ZTMSL-tstar < 0.000001 && tstar-ZTMSL < 0.000001) ZALPH=0.0;
  3397. if ((ZTMSL-tstar > 0.000001 || tstar-ZTMSL > 0.000001) &&
  3398. (GEOS > 0.0001 || GEOS < -0.0001))
  3399. ZALPH=RD*(ZTMSL-tstar)/GEOS;
  3400. if (PRES <= APH) PEVAL = ((APH-PRES)*T+ (PRES-APF)*tstar)/ (APH-APF);
  3401. else
  3402. {
  3403. ZTMSL=Z1;
  3404. tstar=ztsz;
  3405. ZHTS=GEOS*zrg;
  3406. if (ZHTS > 2000. && Z1 > 298.)
  3407. {
  3408. ZTMSL=298.;
  3409. if (ZHTS < 2500.) ZTMSL=0.002*((2500.-ZHTS)*Z1+(ZHTS-2000.)*ZTMSL);
  3410. }
  3411. if ((ZTMSL-tstar) < 0.000001) ZALPH=0.;
  3412. else if (GEOS > 0.0001 || GEOS < -0.0001) ZALPH=RD*(ZTMSL-tstar)/GEOS;
  3413. else ZALPH=RD*RLAPSE*zrg;
  3414. ZALP=ZALPH*log(PRES/APH);
  3415. PEVAL=tstar*(1.0+ZALP*(1.0+ZALP*(0.5+0.16666666667*ZALP)));
  3416. }
  3417. return PEVAL;
  3418. }
  3419. double ExtraZ(double pres, double aph, double apf, double sg, double t)
  3420. {
  3421. double zrg = 1.0 / Grav;
  3422. double alpha,tstar,tmsl,ZALP,ZALPAL;
  3423. alpha = RD * RLAPSE * zrg;
  3424. tstar = (1.0 + alpha * (aph/apf - 1.0)) * t;
  3425. if (tstar < 255.0) tstar = 0.5 * (255.0 + tstar);
  3426. tmsl = tstar + RLAPSE * zrg * sg;
  3427. if (tmsl > 290.5 && tstar > 290.5)
  3428. {
  3429. tstar = 0.5 * (290.5 + tstar);
  3430. tmsl = tstar;
  3431. }
  3432. if (tmsl > 290.5 && tstar <= 290.5) tmsl = 290.5;
  3433. if (tmsl-tstar < 0.000001 && tstar-tmsl < 0.000001) alpha = 0.0;
  3434. else if (sg > 0.0001 || sg < -0.0001) alpha = RD * (tmsl-tstar) / sg;
  3435. ZALP = log(pres/aph);
  3436. ZALPAL = ZALP * alpha;
  3437. return (sg - RD * tstar * ZALP * (1.0 + ZALPAL * (0.5 + ZALPAL/6.0))) * zrg;
  3438. }
  3439. void Interpolate_T(int Code)
  3440. {
  3441. int lp, i;
  3442. int nl,nh;
  3443. double pres;
  3444. int *nx = vert_index;
  3445. double *gt = &All[Code].hgp[0];
  3446. double *pt = &All[Code].pgp[0];
  3447. double *pf = &FullPress->hgp[0];
  3448. double *ph = &HalfPress->hgp[0];
  3449. for (lp = 0; lp < OutLevs; lp++)
  3450. {
  3451. pres = level[lp];
  3452. for (i = 0; i < DimGP; i++)
  3453. {
  3454. nl = i + DimGP * *nx;
  3455. nh = nl + DimGP;
  3456. if (nl < 0) // Above top level
  3457. {
  3458. *pt = gt[i];
  3459. }
  3460. else if (nh >= Dim3GP) // Below bottom level
  3461. {
  3462. if (!mars && Code == TCODE) *pt = ExtraT(pres,ph[nh],pf[nl],Orography[i],gt[nl]);
  3463. else *pt = gt[nl];
  3464. }
  3465. else // Inside
  3466. {
  3467. *pt = gt[nl] + (pres-pf[nl]) * (gt[nh]-gt[nl]) / (pf[nh]-pf[nl]);
  3468. }
  3469. ++nx;
  3470. ++pt;
  3471. }
  3472. }
  3473. }
  3474. void Interpolate_Z(void)
  3475. {
  3476. int lp, i;
  3477. int nl,nh;
  3478. double pres;
  3479. int *nx = vert_index;
  3480. double *gz = &GeopotHeight->hgp[0];
  3481. double *pz = &GeopotHeight->pgp[0];
  3482. double *gt = &Temperature->hgp[0];
  3483. double *pf = &FullPress->hgp[0];
  3484. double *ph = &HalfPress->hgp[0];
  3485. for (lp = 0; lp < OutLevs; lp++)
  3486. {
  3487. pres = level[lp];
  3488. for (i = 0; i < DimGP; i++)
  3489. {
  3490. nl = i + DimGP * *nx;
  3491. if (pres > ph[nl+DimGP]) nl += DimGP;
  3492. nh = nl + DimGP;
  3493. if (nl < 0) // Above top level
  3494. {
  3495. *pz = gz[i];
  3496. }
  3497. else if (nl >= Dim3GP) // Below bottom level
  3498. {
  3499. if (mars) *pz = gz[nl-DimGP];
  3500. else *pz = ExtraZ(pres,ph[nl], pf[nl-DimGP],Orography[i],gt[nl-DimGP]);
  3501. }
  3502. else // Inside
  3503. {
  3504. *pz = gz[nl] + (pres-ph[nl]) * (gz[nh]-gz[nl]) / (ph[nh] - ph[nl]);
  3505. }
  3506. ++nx;
  3507. ++pz;
  3508. }
  3509. }
  3510. }
  3511. void CheckDependencies(void)
  3512. {
  3513. u_wind->needed = ( Divergence->needed && !Divergence->detected) ||
  3514. ( Vorticity->needed && !Vorticity->detected) ||
  3515. ( VeloPot->needed && !VeloPot->detected) ||
  3516. ( StreamF->needed && !StreamF->detected) ||
  3517. ( Omega->needed && !Omega->detected) ||
  3518. ( speed->needed && !speed->detected) ||
  3519. ( v_wind->needed && !v_wind->detected) ||
  3520. u_wind->selected;
  3521. v_wind->needed = ( Divergence->needed && !Divergence->detected) ||
  3522. ( Vorticity->needed && !Vorticity->detected) ||
  3523. ( VeloPot->needed && !VeloPot->detected) ||
  3524. ( StreamF->needed && !StreamF->detected) ||
  3525. ( Omega->needed && !Omega->detected) ||
  3526. ( speed->needed && !speed->detected) ||
  3527. ( u_wind->needed && !u_wind->detected) ||
  3528. v_wind->selected;
  3529. Divergence->needed = ( u_wind->needed && !u_wind->detected) ||
  3530. ( v_wind->needed && !v_wind->detected) ||
  3531. ( Omega->needed && !Omega->detected) ||
  3532. ( VeloPot->needed && !VeloPot->detected) ||
  3533. Divergence->selected;
  3534. Vorticity->needed = ( u_wind->needed && !u_wind->detected) ||
  3535. ( v_wind->needed && !v_wind->detected) ||
  3536. ( StreamF->needed && !StreamF->detected) ||
  3537. Vorticity->selected;
  3538. Humidity->needed = (GeopotHeight->needed && !GeopotHeight->detected) ||
  3539. ( Rhumidity->needed && !Rhumidity->detected) ||
  3540. Humidity->selected;
  3541. Ps->needed |= dpsdx->needed || dpsdy->needed ||
  3542. Rhumidity->needed || Omega->needed;
  3543. LnPs->needed |= Ps->needed;
  3544. Temperature->needed = (GeopotHeight->needed && !GeopotHeight->detected) ||
  3545. ( Rhumidity->needed && !Rhumidity->detected) ||
  3546. ( SLP->needed && !SLP->detected) ||
  3547. ( w_wind->needed && !w_wind->detected) ||
  3548. Temperature->selected;
  3549. All[176].needed = ( net_heat->needed && !net_heat->detected) ||
  3550. ( net_bot->needed && !net_bot->detected) ||
  3551. ( net_atm->needed && !net_atm->detected) ||
  3552. ( sw_atm->needed && !sw_atm->detected) ||
  3553. All[176].selected;
  3554. All[177].needed = ( net_heat->needed && !net_heat->detected) ||
  3555. ( net_bot->needed && !net_bot->detected) ||
  3556. ( net_atm->needed && !net_atm->detected) ||
  3557. ( lw_atm->needed && !lw_atm->detected) ||
  3558. All[177].selected;
  3559. All[178].needed = ( net_top->needed && !net_top->detected) ||
  3560. ( net_atm->needed && !net_atm->detected) ||
  3561. ( sw_atm->needed && !sw_atm->detected) ||
  3562. All[178].selected;
  3563. All[179].needed = ( net_top->needed && !net_top->detected) ||
  3564. ( net_atm->needed && !net_atm->detected) ||
  3565. ( lw_atm->needed && !lw_atm->detected) ||
  3566. All[179].selected;
  3567. }
  3568. void CheckContent(void)
  3569. {
  3570. int code;
  3571. for (code = 0; code < 256; code++)
  3572. {
  3573. if (code == GEOSCODE) continue;
  3574. if (code == SLPCODE) continue;
  3575. if (code == ZCODE) continue;
  3576. if (code == STRCODE) continue;
  3577. if (code == VELCODE) continue;
  3578. if (code == UCODE) continue;
  3579. if (code == VCODE) continue;
  3580. if (code == WCODE) continue;
  3581. if (code == RHCODE) continue;
  3582. if (code == PSCODE) continue;
  3583. if (code == WZCODE) continue;
  3584. if (code == SHCODE)
  3585. {
  3586. if (All[code].needed && !All[code].selected &&
  3587. All[code].hsp.size() == 0 &&
  3588. All[code].hgp.size() == 0 &&
  3589. HumInfo == 0)
  3590. {
  3591. printf("\n ********* I N F O **********\n");
  3592. printf( " * No humidity in data file *\n");
  3593. printf( " * Humidity set to zero ! *\n");
  3594. printf( " ****************************\n");
  3595. All[code].needed = FALSE;
  3596. HumInfo = 1;
  3597. }
  3598. }
  3599. else
  3600. {
  3601. if (All[code].needed &&
  3602. All[code].hsp.size() == 0 &&
  3603. All[code].hgp.size() == 0)
  3604. {
  3605. printf("\n ****** E R R O R ******\n");
  3606. printf(" * Code %3d not found *\n",code);
  3607. printf(" ***********************\n");
  3608. exit(1);
  3609. }
  3610. }
  3611. }
  3612. }
  3613. void Dependencies(void)
  3614. {
  3615. int code;
  3616. for (code = 0; code < CODES; code++)
  3617. All[code].needed = All[code].selected;
  3618. CheckDependencies();
  3619. if (OutRep >= PRE_GRID)
  3620. {
  3621. u_wind->needed |= Divergence->needed;
  3622. v_wind->needed |= Divergence->needed;
  3623. u_wind->needed |= Vorticity->needed;
  3624. v_wind->needed |= Vorticity->needed;
  3625. u_wind->needed |= VeloPot->needed;
  3626. v_wind->needed |= VeloPot->needed;
  3627. u_wind->needed |= StreamF->needed;
  3628. v_wind->needed |= StreamF->needed;
  3629. }
  3630. Omega->needed |= w_wind->needed;
  3631. dpsdx->needed |= Omega->needed;
  3632. dpsdy->needed |= Omega->needed;
  3633. if (VerType == 'p')
  3634. {
  3635. LnPs->needed = TRUE;
  3636. Divergence->needed |= Omega->needed;
  3637. u_wind->needed |= Omega->needed;
  3638. v_wind->needed |= Omega->needed;
  3639. u_wind->needed |= speed->needed;
  3640. v_wind->needed |= speed->needed;
  3641. Temperature->needed |= Omega->needed || SLP->needed;
  3642. Humidity->needed |= GeopotHeight->needed || Rhumidity->needed;
  3643. Temperature->needed |= GeopotHeight->needed || Rhumidity->needed ||
  3644. ThetaF->needed;
  3645. }
  3646. Divergence->needed |= u_wind->needed || v_wind->needed;
  3647. Vorticity->needed |= u_wind->needed || v_wind->needed;
  3648. Divergence->needed |= VeloPot->needed;
  3649. Vorticity->needed |= StreamF->needed;
  3650. LnPs->needed |= HalfPress->needed || dpsdx->needed ||
  3651. Ps->needed || Rhumidity->needed;
  3652. All[139].needed |= ThetaF->selected;
  3653. All[142].needed |= precip->selected || net_water->selected ||
  3654. fresh_water->selected || surf_runoff->selected;
  3655. All[143].needed |= precip->selected || net_water->selected ||
  3656. fresh_water->selected || surf_runoff->selected;
  3657. All[146].needed |= net_heat->selected; /* sensible heat */
  3658. All[147].needed |= net_heat->selected; /* latent heat */
  3659. All[160].needed |= net_water->selected; /* Runoff */
  3660. All[176].needed |= net_heat->selected ||
  3661. net_bot->selected ||
  3662. net_atm->selected || sw_atm->selected;
  3663. All[177].needed |= net_heat->selected ||
  3664. net_bot->selected ||
  3665. net_atm->selected || lw_atm->selected;
  3666. All[178].needed |= net_top->selected ||
  3667. net_atm->selected || sw_atm->selected;
  3668. All[179].needed |= net_top->selected ||
  3669. net_atm->selected || lw_atm->selected;
  3670. All[182].needed |= net_water->selected ||
  3671. fresh_water->selected || surf_runoff->selected;
  3672. All[218].needed |= net_heat->selected; /* snow melt */
  3673. All[221].needed |= surf_runoff->selected; /* snow depth change */
  3674. }
  3675. void Speed(double *speed, double *u, double *v)
  3676. {
  3677. int i;
  3678. for (i = 0; i < Dim3GP; i++)
  3679. speed[i] = sqrt(u[i] * u[i] + v[i] * v[i]);
  3680. }
  3681. // ======================================================
  3682. // Compute derivation d(LnPs)/d(sin phi) in fourier space
  3683. // ======================================================
  3684. void Deriva(double field[], double derilam[])
  3685. {
  3686. int l,n;
  3687. int i;
  3688. i = 0;
  3689. for (n = 0; n < Waves ; n++)
  3690. {
  3691. for (l = 0; l < Lats; l++,i++) // cosine coefficients
  3692. derilam[i] = -n * field[i+Lats] * DerivationFactor[l];
  3693. for (l = 0; l < Lats; l++,i++) // sine coefficients
  3694. derilam[i] = n * field[i-Lats] * DerivationFactor[l];
  3695. }
  3696. }
  3697. void scaluv(double *fu, double Factor[], int nlat, int nlot)
  3698. {
  3699. for (int lot = 0; lot < nlot; lot++)
  3700. for (int lat = 0; lat < nlat; lat++)
  3701. {
  3702. *fu++ *= Factor[lat];
  3703. }
  3704. }
  3705. void uv2dv(double *fu, double *fv, double *sd, double *sv,
  3706. double *pol2, double *poli, int klev, int nlat, int nt)
  3707. {
  3708. int lev,jmm,jfc,lat;
  3709. double dir,dii,vor,voi;
  3710. double *ufr,*ufi,*vfr,*vfi;
  3711. double *po2,*pod;
  3712. double zo2, zod;
  3713. double gmuq;
  3714. for (lev = 0; lev < klev; lev++)
  3715. {
  3716. if (PolyDisk)
  3717. {
  3718. rewind(pol2f);
  3719. rewind(polif);
  3720. }
  3721. po2 = pol2;
  3722. pod = poli;
  3723. for (jmm = 0; jmm <= nt; jmm++)
  3724. {
  3725. for (jfc = jmm; jfc <= nt; jfc++)
  3726. {
  3727. ufr = fu ;
  3728. ufi = fu + nlat ;
  3729. vfr = fv ;
  3730. vfi = fv + nlat ;
  3731. dir = 0.0 ;
  3732. dii = 0.0 ;
  3733. vor = 0.0 ;
  3734. voi = 0.0 ;
  3735. if (PolyDisk)
  3736. {
  3737. fread(po2=pol2,sizeof(double),Lats,pol2f);
  3738. fread(pod=poli,sizeof(double),Lats,polif);
  3739. }
  3740. for (lat = 0; lat < nlat; lat++)
  3741. {
  3742. gmuq = 1.0 - Outlat->gmu[lat] * Outlat->gmu[lat];
  3743. zod = *pod * 0.5 * jmm * Outlat->gwt[lat] / (PlanetRadius * gmuq);
  3744. zo2 = *po2 * Outlat->gwt[lat] / gmuq;
  3745. dir += *vfr * zo2 - *ufi * zod;
  3746. dii += *vfi * zo2 + *ufr * zod;
  3747. vor -= *ufr * zo2 + *vfi * zod;
  3748. voi -= *ufi * zo2 - *vfr * zod;
  3749. ufr++;
  3750. ufi++;
  3751. vfr++;
  3752. vfi++;
  3753. po2++;
  3754. pod++;
  3755. }
  3756. *sd++ = dir;
  3757. *sd++ = dii;
  3758. *sv++ = vor;
  3759. *sv++ = voi;
  3760. }
  3761. fu += 2 * nlat;
  3762. fv += 2 * nlat;
  3763. }
  3764. }
  3765. }
  3766. void genind(int *Interpolation_Index, double lv[],
  3767. double *Full_Level_Pressure, int DimGP, int OutLevs)
  3768. {
  3769. int h,k,l;
  3770. int *nx;
  3771. double Pressure,*pf;
  3772. nx = Interpolation_Index;
  3773. for (h=0 ; h < DimGP * OutLevs ; ++h) nx[h] = -1;
  3774. for (k = 0; k<OutLevs; k++)
  3775. {
  3776. Pressure = lv[k];
  3777. pf = Full_Level_Pressure;
  3778. for (l = 0; l<SigLevs; l++)
  3779. for (h = 0; h<DimGP ; h++)
  3780. {
  3781. if (Pressure > *pf) nx[h] = l;
  3782. pf++;
  3783. }
  3784. nx += DimGP;
  3785. }
  3786. }
  3787. void theta(double *PThetaF, double *PThetaH, double *PH, double *PS,
  3788. double *TF, double *TS, int DimGP, int Dim3GP)
  3789. {
  3790. int h,l;
  3791. double Kappa = RD / RCPD;
  3792. double *ThetaH = PThetaH;
  3793. double *ThetaF = PThetaF;
  3794. for (h = 0; h < DimGP; h++) ThetaH[h] = 0.0;
  3795. ThetaH += DimGP;
  3796. for (l = 0; l < SigLevs - 1; l++)
  3797. {
  3798. for (h = 0; h < DimGP; h++)
  3799. {
  3800. ThetaH[h] = 0.5 * (TF[h] + TF[h+DimGP]) * pow((PS[h]/PH[h]),Kappa);
  3801. }
  3802. PH += DimGP;
  3803. TF += DimGP;
  3804. ThetaH += DimGP;
  3805. }
  3806. memcpy(ThetaH,TS,DimGP * sizeof(double));
  3807. ThetaH = PThetaH;
  3808. for (h = 0; h < Dim3GP; h++)
  3809. {
  3810. ThetaF[h] = 0.5 * (ThetaH[h] + ThetaH[h+DimGP]);
  3811. }
  3812. }
  3813. void presh(double *pf, double *php, double *vct, double *ps)
  3814. {
  3815. int h,l;
  3816. double zp,ze;
  3817. double *ph = php;
  3818. for (l = 0; l<SigLevs; l++)
  3819. {
  3820. zp = vct[l];
  3821. ze = vct[l+SigLevs+1];
  3822. for (h = 0; h<DimGP; h++) ph[h] = zp + ze * ps[h];
  3823. ph += DimGP;
  3824. }
  3825. memcpy(ph,ps,DimGP * sizeof(double));
  3826. ph = php;
  3827. for (h = 0; h<Dim3GP; h++) pf[h] = 0.5 * (ph[h] + ph[h+DimGP]);
  3828. }
  3829. /*****************************/
  3830. /* Compute relative humidity */
  3831. /*****************************/
  3832. double relhum(double q, double t, double p)
  3833. {
  3834. double rh;
  3835. double gascon;
  3836. double rv;
  3837. double TMELT;
  3838. double ra1;
  3839. double ra2;
  3840. double ra4;
  3841. double rdbrv;
  3842. double zqsat;
  3843. rv = 461.51;
  3844. TMELT = 273.16;
  3845. gascon = 287.0 ;
  3846. ra1 = 610.78;
  3847. ra2 = 17.2693882;
  3848. ra4 = 35.86;
  3849. rdbrv = gascon / rv;
  3850. zqsat = rdbrv * ra1 * exp(ra2 * (t-TMELT) / (t-ra4)) / p;
  3851. zqsat *= 1.0 / (1.0 - (1.0 / rdbrv - 1.0) * zqsat);
  3852. rh = q * 100.0 / zqsat;
  3853. if (rh < 0.0) rh = 0.0;
  3854. if (rh > 100.0) rh = 100.0;
  3855. return rh;
  3856. }
  3857. /*****************************/
  3858. /* Compute relative humidity */
  3859. /*****************************/
  3860. void sh2rh(double *sphum, double *rhum, double *t, int lev)
  3861. {
  3862. int jhor,jlev;
  3863. double *pp; // pressure
  3864. pp = &FullPress->hgp[0];
  3865. for (jlev = 0; jlev < lev; jlev++)
  3866. for (jhor = 0; jhor < DimGP; jhor++)
  3867. *rhum++ = relhum(*sphum++,*t++,*pp++);
  3868. }
  3869. void dv2ps(double *div, double *pot, int lev)
  3870. {
  3871. for (int l = 0; l < lev ; l++)
  3872. for (int m = 0; m <= Truncation; m++)
  3873. for (int n = m; n <= Truncation; n++)
  3874. {
  3875. if (n)
  3876. {
  3877. *pot++ = *div++ * SQUARE_RADIUS / (n * n + n);
  3878. *pot++ = *div++ * SQUARE_RADIUS / (n * n + n);
  3879. }
  3880. else
  3881. {
  3882. *pot++ = 0.0;
  3883. *pot++ = 0.0;
  3884. div += 2;
  3885. }
  3886. }
  3887. }
  3888. void MakeGeopotHeight(double *geop, double* gt, double *gq, double *ph, int nhor, int nlev)
  3889. {
  3890. int i;
  3891. double VTMP = (RV / RD) - 1.0;
  3892. double zrg = 1.0 / Grav;
  3893. if (gq) /* Humidity is present */ {
  3894. for (i = nhor * nlev - 1; i >= nhor; i--)
  3895. geop[i] = geop[i+nhor] + RD * gt[i] * (1.0 + VTMP * gq[i])
  3896. * log(ph[i+nhor] / ph[i]);
  3897. for (i = 0; i < nhor; i++)
  3898. geop[i] = geop[i+nhor] + RD * gt[i] * (1.0 + VTMP * gq[i])
  3899. * 2.0 * log(2.0);
  3900. }
  3901. else /* No humidity */ {
  3902. for (i = nhor * nlev - 1; i >= nhor; i--)
  3903. geop[i] = geop[i+nhor] + RD * gt[i] * log(ph[i+nhor] / ph[i]);
  3904. for (i = 0; i < nhor; i++)
  3905. geop[i] = geop[i+nhor] + RD * gt[i] * 2.0 * log(2.0);
  3906. }
  3907. for (i = 0; i < nhor * (nlev+1); i++) geop[i] *= zrg;
  3908. }
  3909. void gp2fc_uv(void)
  3910. {
  3911. u_wind->SetPFour();
  3912. v_wind->SetPFour();
  3913. gp2fc(&u_wind->pgp[0],&u_wind->pfc[0],Lats,Lons,OutLevs,Fouriers);
  3914. gp2fc(&v_wind->pgp[0],&v_wind->pfc[0],Lats,Lons,OutLevs,Fouriers);
  3915. }
  3916. void fc2sp_uv(void)
  3917. {
  3918. scaluv(&u_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
  3919. scaluv(&v_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
  3920. u_wind->SetPSpec();
  3921. v_wind->SetPSpec();
  3922. Divergence->SetPSpec();
  3923. Vorticity->SetPSpec();
  3924. fc2sp(&u_wind->pfc[0],&u_wind->psp[0],OutLevs,Lats,Truncation);
  3925. fc2sp(&v_wind->pfc[0],&v_wind->psp[0],OutLevs,Lats,Truncation);
  3926. uv2dv(&u_wind->pfc[0],&v_wind->pfc[0],
  3927. &Divergence->psp[0],&Vorticity->psp[0],pol2,poli,OutLevs,Lats,Truncation);
  3928. if (VeloPot->needed)
  3929. {
  3930. VeloPot->plev = OutLevs;
  3931. VeloPot->SetPSpec();
  3932. dv2ps(&Divergence->psp[0],&VeloPot->psp[0],OutLevs);
  3933. }
  3934. if (StreamF->needed)
  3935. {
  3936. StreamF->plev = OutLevs;
  3937. StreamF->SetPSpec();
  3938. dv2ps(&Vorticity->psp[0],&StreamF->psp[0],OutLevs);
  3939. }
  3940. }
  3941. void sp2fc_uv(void)
  3942. {
  3943. for (int si = 0 ; si < 4 ; ++si)
  3944. {
  3945. int code = SpecialCodes[si];
  3946. if (All[code].selected && All[code].psp.size())
  3947. {
  3948. All[code].SetPFour();
  3949. sp2fci(&All[code].psp[0],&All[code].pfc[0],OutLevs);
  3950. }
  3951. }
  3952. if (u_wind->selected && u_wind->pfc.size())
  3953. scaluv(&u_wind->pfc[0],RevCosPhi,Lats,Fouriers*OutLevs);
  3954. if (v_wind->selected && v_wind->pfc.size())
  3955. scaluv(&v_wind->pfc[0],RevCosPhi,Lats,Fouriers*OutLevs);
  3956. }
  3957. void fc2gp_uv(void)
  3958. {
  3959. for (int si = 0 ; si < 4 ; ++si)
  3960. {
  3961. int code = SpecialCodes[si];
  3962. if (All[code].selected && All[code].pfc.size())
  3963. {
  3964. All[code].SetPGrid();
  3965. fc2gp(&All[code].pfc[0],&All[code].pgp[0],Lats,Lons,OutLevs,Fouriers);
  3966. }
  3967. }
  3968. }
  3969. void PumaProcess(void)
  3970. {
  3971. int code;
  3972. MeanCount++; // Count term inside month
  3973. TermCount++; // Count term
  3974. #ifdef NETCDF_OUTPUT
  3975. if (TermCount == 1 && NetCDF) NetVarDefine(); // Define NetCDF variables
  3976. #endif
  3977. if (MeanCount == 1) CheckContent(); // Everything OK ?
  3978. if (TermCount > 60) Debug = 0; // Limit debug output
  3979. // Reset level offset for all variables
  3980. for (code = 0; code < CODES; code++) All[code].loff = 0;
  3981. // Derive velocity potential and streamfunction from divergence and vorticity
  3982. if (VeloPot->needed && !VeloPot->detected && VerType == 's')
  3983. {
  3984. VeloPot->SetHSpec(SigLevs,OutLevs,FALSE);
  3985. dv2ps(&Divergence->hsp[0],&VeloPot->hsp[0],SigLevs);
  3986. }
  3987. if (StreamF->needed && !StreamF->detected && VerType == 's')
  3988. {
  3989. StreamF->SetHSpec(SigLevs,OutLevs,FALSE);
  3990. dv2ps(&Vorticity->hsp[0],&StreamF->hsp[0],SigLevs);
  3991. }
  3992. // -------------------------
  3993. // Output of spectral fields
  3994. // -------------------------
  3995. if (OutRep == HYB_SPEC)
  3996. {
  3997. HybSpec->Write_hspec();
  3998. return;
  3999. }
  4000. // =====================================================
  4001. // Transformation from spectral domain to fourier domain
  4002. // =====================================================
  4003. // Derive wind components u*cos(phi) and v*cos(phi)
  4004. if ((u_wind->needed || v_wind->needed) &&
  4005. (!u_wind->detected || !v_wind->detected))
  4006. {
  4007. u_wind->SetHFour(SigLevs,OutLevs,FALSE);
  4008. v_wind->SetHFour(SigLevs,OutLevs,FALSE);
  4009. spvfc(&Divergence->hsp[0],&Vorticity->hsp[0],
  4010. &u_wind->hfc[0] ,&v_wind->hfc[0] ,
  4011. Divergence->hlev ,Lats,Fouriers,Truncation);
  4012. }
  4013. // If divergence and vorticity were needed for u and v computation
  4014. // only, they are now released
  4015. Vorticity->needed = Vorticity->selected;
  4016. Divergence->needed = Divergence->selected || Omega->needed;
  4017. // Perform inverse Legendre transformation for all needed variables
  4018. for (code = 0 ; code < CODES; code++)
  4019. if (All[code].needed && All[code].hsp.size())
  4020. {
  4021. All[code].SetHFour(All[code].hlev,All[code].plev,All[code].twod);
  4022. sp2fci(&All[code].hsp[0],&All[code].hfc[0],All[code].hlev);
  4023. }
  4024. // Compute d(Lnps)/dx and d(Lnps)/dy if needed
  4025. if (dpsdx->needed || dpsdy->needed)
  4026. {
  4027. dpsdx->SetHFour(1,1,TRUE);
  4028. dpsdy->SetHFour(1,1,TRUE);
  4029. Deriva(&LnPs->hfc[0],&dpsdx->hfc[0]);
  4030. sp2fcd(&LnPs->hsp[0],&dpsdy->hfc[0],1,Lats,Fouriers,Truncation);
  4031. }
  4032. /* ------------------------ */
  4033. /* Output of fourier fields */
  4034. /* ------------------------ */
  4035. if (OutRep == HYB_FOUR)
  4036. {
  4037. HybFour->Write_hfour();
  4038. return;
  4039. }
  4040. /* --------------------- */
  4041. /* Output of zonal means */
  4042. /* --------------------- */
  4043. if (OutRep == HYB_ZONM)
  4044. {
  4045. HybSect->Write_hfour();
  4046. return;
  4047. }
  4048. /* ============================ */
  4049. /* Transformation to gridpoints */
  4050. /* ============================ */
  4051. if (SaveMemory) HybSpec->Clear_hspec();
  4052. for (code = 0; code < CODES; code++)
  4053. if (All[code].needed && All[code].hfc.size())
  4054. {
  4055. All[code].SetHGrid(All[code].hlev,All[code].plev,All[code].twod);
  4056. fc2gp(&All[code].hfc[0],&All[code].hgp[0],Lats,Lons,All[code].hlev,Fouriers);
  4057. }
  4058. if (SaveMemory) HybSpec->Clear_hfour();
  4059. if (Humidity->hgp.size()) // Remove spurious negative humidity
  4060. {
  4061. for (int i=0 ; i < Dim3GP ; ++i)
  4062. if (Humidity->hgp[i] < 0.0) Humidity->hgp[i] = 0.0;
  4063. }
  4064. if (LnPs->hgp.size())
  4065. {
  4066. Ps->SetHGrid(1,1,TRUE);
  4067. Ps->hgp = exp(LnPs->hgp);
  4068. }
  4069. LnPs->needed = LnPs->selected;
  4070. if (Orography.size() != DimGP)
  4071. {
  4072. Orography.resize(DimGP);
  4073. if (Geopotential->hgp.size()) Orography = Geopotential->hgp;
  4074. else
  4075. {
  4076. if (Geopotential->selected || VerType == 'p')
  4077. {
  4078. CenterText("Orography not found - using zero orography");
  4079. Orography = 0.0;
  4080. }
  4081. }
  4082. }
  4083. Geopotential->needed = Geopotential->selected;
  4084. if (Geopotential->needed && !Geopotential->hgp.size())
  4085. {
  4086. Geopotential->SetHGrid(1,1,TRUE);
  4087. Geopotential->hgp = Orography;
  4088. }
  4089. // This section is implemented for pressure level fields only
  4090. if (VerType == 'p' || Omega->needed)
  4091. {
  4092. FullPress->SetHGrid(SigLevs ,OutLevs,FALSE);
  4093. HalfPress->SetHGrid(SigLevs+1,OutLevs,FALSE);
  4094. presh(&FullPress->hgp[0],&HalfPress->hgp[0],vct,&Ps->hgp[0]);
  4095. if (ThetaF->needed)
  4096. {
  4097. ThetaF->SetHGrid(SigLevs,OutLevs,FALSE);
  4098. ThetaH->SetHGrid(SigLevs,OutLevs,FALSE);
  4099. theta(&ThetaF->hgp[0], &ThetaH->hgp[0], &HalfPress->hgp[0], &Ps->hgp[0],
  4100. &Temperature->hgp[0], &Ts->hgp[0], DimGP, Dim3GP);
  4101. }
  4102. if (GeopotHeight->needed)
  4103. {
  4104. GeopotHeight->SetHGrid(SigLevs+1,OutLevs,FALSE);
  4105. memcpy(&GeopotHeight->hgp[Dim3GP],&Orography[0],DimGP * sizeof(double));
  4106. MakeGeopotHeight(&GeopotHeight->hgp[0],&Temperature->hgp[0],
  4107. &Humidity->hgp[0],&HalfPress->hgp[0],DimGP,SigLevs);
  4108. Humidity->needed = Humidity->selected;
  4109. }
  4110. if (dpsdx->needed) dpsdx->hgp *= Ps->hgp;
  4111. if (dpsdy->needed) dpsdy->hgp *= Ps->hgp;
  4112. if (Omega->needed)
  4113. {
  4114. Omega->SetHGrid(SigLevs+1,OutLevs,FALSE);
  4115. OMEGA();
  4116. dpsdx->needed = dpsdx->selected;
  4117. dpsdy->needed = dpsdy->selected;
  4118. }
  4119. if (w_wind->needed)
  4120. {
  4121. w_wind->SetHGrid(SigLevs,OutLevs,FALSE);
  4122. Omega_w(&w_wind->hgp[0],&Omega->hgp[0],&Temperature->hgp[0],&FullPress->hgp[0]);
  4123. }
  4124. if (Rhumidity->needed)
  4125. {
  4126. Rhumidity->SetHGrid(SigLevs,OutLevs,FALSE);
  4127. sh2rh(&Humidity->hgp[0],&Rhumidity->hgp[0],
  4128. &Temperature->hgp[0],SigLevs);
  4129. Temperature->needed = Temperature->selected;
  4130. Humidity->needed = Humidity->selected;
  4131. }
  4132. if (SLP->needed)
  4133. {
  4134. SLP->SetHGrid(1,1,TRUE);
  4135. Extrap(&SLP->hgp[0],&HalfPress->hgp[0] + Dim3GP,
  4136. &FullPress->hgp[0] + Dim3GP - DimGP , &Orography[0],
  4137. &Temperature->hgp[0] + Dim3GP - DimGP , DimGP);
  4138. Temperature->needed = Temperature->selected || GeopotHeight->selected;
  4139. }
  4140. } // endif (VerType == 'p')
  4141. if (speed->needed)
  4142. {
  4143. speed->SetHGrid(SigLevs,OutLevs,FALSE);
  4144. Speed(&speed->hgp[0],&u_wind->hgp[0],&v_wind->hgp[0]);
  4145. }
  4146. if (precip->needed)
  4147. {
  4148. precip->SetHGrid(1,1,TRUE);
  4149. precip->hgp = All[142].hgp + All[143].hgp;
  4150. }
  4151. if (net_top->needed)
  4152. {
  4153. net_top->SetHGrid(1,1,TRUE);
  4154. net_top->hgp = All[178].hgp + All[179].hgp;
  4155. }
  4156. if (net_bot->needed)
  4157. {
  4158. net_bot->SetHGrid(1,1,TRUE);
  4159. net_bot->hgp = All[176].hgp + All[177].hgp;
  4160. }
  4161. if (net_heat->needed)
  4162. {
  4163. net_heat->SetHGrid(1,1,TRUE);
  4164. net_heat->hgp = All[218].hgp * L_times_rhoH2O
  4165. + All[176].hgp + All[177].hgp + All[146].hgp + All[147].hgp;
  4166. }
  4167. if (net_water->needed)
  4168. {
  4169. net_water->SetHGrid(1,1,TRUE);
  4170. net_water->hgp = All[182].hgp - All[160].hgp + All[142].hgp + All[143].hgp;
  4171. }
  4172. if (sw_atm->needed)
  4173. {
  4174. sw_atm->SetHGrid(1,1,TRUE);
  4175. sw_atm->hgp = All[178].hgp - All[176].hgp;
  4176. }
  4177. if (lw_atm->needed)
  4178. {
  4179. lw_atm->SetHGrid(1,1,TRUE);
  4180. lw_atm->hgp = All[179].hgp - All[177].hgp;
  4181. }
  4182. if (net_atm->needed)
  4183. {
  4184. net_atm->SetHGrid(1,1,TRUE);
  4185. net_atm->hgp = All[178].hgp + All[179].hgp - All[176].hgp - All[177].hgp;
  4186. }
  4187. if (surf_runoff->needed)
  4188. {
  4189. surf_runoff->SetHGrid(1,1,TRUE);
  4190. surf_runoff->hgp = All[182].hgp - All[221].hgp + All[142].hgp + All[143].hgp;
  4191. }
  4192. if (fresh_water->needed)
  4193. {
  4194. fresh_water->SetHGrid(1,1,TRUE);
  4195. fresh_water->hgp = All[142].hgp + All[143].hgp + All[182].hgp;
  4196. }
  4197. // =============================
  4198. // Monthly means on hybrid grids
  4199. // =============================
  4200. if (Mean && OutRep == HYB_GRID)
  4201. for (code = 0; code < CODES; code++)
  4202. if (All[code].selected && All[code].hgp.size())
  4203. {
  4204. if (MeanCount == 1)
  4205. {
  4206. All[code].mgp.resize(All[code].hgp.size());
  4207. All[code].mgp = All[code].hgp;
  4208. All[code].hgp.resize(0);
  4209. }
  4210. else All[code].mgp += All[code].hgp;
  4211. if (EndOfMonth)
  4212. {
  4213. double rmc = 1.0 / MeanCount;
  4214. All[code].hgp = All[code].mgp * rmc;
  4215. All[code].mgp.resize(0);
  4216. }
  4217. }
  4218. // ----------------------------
  4219. // Output of hybrid level grids
  4220. // ----------------------------
  4221. if (OutRep == HYB_GRID)
  4222. {
  4223. if (!Mean || EndOfMonth) HybGrid->Write_hgrid();
  4224. if (SaveMemory) HybGrid->Clear_hgrid();
  4225. return;
  4226. }
  4227. // ======================================
  4228. // Vertical interpolation / extrapolation
  4229. // ======================================
  4230. if (vert_index == NULL) vert_index = new int[OutLevs*DimGP];
  4231. genind(vert_index,level,&FullPress->hgp[0],DimGP,OutLevs);
  4232. for (code = 0; code < CODES; code++)
  4233. if (All[code].needed && All[code].hgp.size())
  4234. {
  4235. All[code].SetPGrid();
  4236. if (!All[code].twod)
  4237. {
  4238. if (code == ZCODE) Interpolate_Z();
  4239. else Interpolate_T(code);
  4240. }
  4241. }
  4242. Temperature->needed = Temperature->selected;
  4243. if (SaveMemory) HybGrid->Clear_hgrid();
  4244. // ===========================
  4245. // Computation of Montly Means
  4246. // ===========================
  4247. if (Mean)
  4248. for (code = 0; code < CODES; code++)
  4249. if (All[code].needed && All[code].pgp.size())
  4250. {
  4251. if (MeanCount == 1)
  4252. {
  4253. All[code].mgp.resize(All[code].pgp.size());
  4254. All[code].mgp = All[code].pgp;
  4255. All[code].pgp.resize(0);
  4256. }
  4257. else All[code].mgp += All[code].pgp;
  4258. if (EndOfMonth)
  4259. {
  4260. double rmc = 1.0 / MeanCount;
  4261. All[code].pgp = All[code].mgp * rmc;
  4262. All[code].mgp.resize(0);
  4263. }
  4264. }
  4265. if (Mean && !EndOfMonth)
  4266. {
  4267. if (SaveMemory) HybGrid->Clear_pgrid();
  4268. return;
  4269. }
  4270. // ------------------------------
  4271. // Output of pressure level grids
  4272. // ------------------------------
  4273. if (OutRep == PRE_GRID)
  4274. {
  4275. if (SpecialUV)
  4276. {
  4277. gp2fc_uv();
  4278. fc2sp_uv();
  4279. sp2fc_uv();
  4280. fc2gp_uv();
  4281. }
  4282. HybGrid->Write_pgrid();
  4283. if (SaveMemory) HybGrid->Clear_pgrid();
  4284. return;
  4285. }
  4286. // ===============================
  4287. // Transformation to fourier space
  4288. // ===============================
  4289. for (code = 0; code < CODES; code++)
  4290. if (All[code].needed && All[code].pgp.size())
  4291. {
  4292. if (!All[code].pfc.size()) All[code].SetPFour();
  4293. gp2fc(&All[code].pgp[0],&All[code].pfc[0],
  4294. Lats,Lons,All[code].plev,Fouriers);
  4295. }
  4296. if (SaveMemory) HybGrid->Clear_pgrid();
  4297. // ---------------------------------------
  4298. // Output of fourier fields or zonal means
  4299. // ---------------------------------------
  4300. if (OutRep == PRE_FOUR || OutRep == PRE_ZONM)
  4301. {
  4302. if (SpecialUV)
  4303. {
  4304. fc2sp_uv();
  4305. sp2fc_uv();
  4306. }
  4307. if (OutRep == PRE_FOUR) HybFour->Write_pfour();
  4308. else HybSect->Write_pfour();
  4309. if (SaveMemory) HybFour->Clear_pfour();
  4310. return;
  4311. }
  4312. // ================================
  4313. // Transformation to spectral space
  4314. // ================================
  4315. if (!SpecialUV && u_wind->pfc.size() && v_wind->pfc.size())
  4316. {
  4317. scaluv(&u_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
  4318. scaluv(&v_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
  4319. }
  4320. for (code = 0; code < CODES; code++)
  4321. if (All[code].needed && All[code].pfc.size() && !All[code].psp.size())
  4322. {
  4323. All[code].SetPSpec();
  4324. fc2sp(&All[code].pfc[0],&All[code].psp[0],All[code].plev,Lats,Truncation);
  4325. }
  4326. if (SpecialUV) fc2sp_uv();
  4327. if (SaveMemory) HybFour->Clear_pfour();
  4328. // -------------------------
  4329. // Output of spectral fields
  4330. // -------------------------
  4331. if (OutRep == PRE_SPEC)
  4332. {
  4333. HybSpec->Write_pspec();
  4334. if (SaveMemory) HybSpec->Clear_pspec();
  4335. return;
  4336. }
  4337. }
  4338. void PostProcess(void)
  4339. {
  4340. int l;
  4341. char tb[COLS+2];
  4342. if (EndOfMonth)
  4343. {
  4344. sprintf(tb,"Processed Month %2d Year %4d", OldMonth,OldDate.tm_year);
  4345. l = strlen(tb);
  4346. if (MeanCount > 1)
  4347. {
  4348. if (Mean) sprintf(tb+l," (Mean of %3d Terms)",MeanCount);
  4349. else sprintf(tb+l," Terms %3d",MeanCount);
  4350. }
  4351. LeftText(tb);
  4352. EndOfMonth = FALSE;
  4353. MeanCount = 0;
  4354. MonthCount++ ;
  4355. }
  4356. }
  4357. /* ================= */
  4358. /* switch input file */
  4359. /* ================= */
  4360. void SwitchFile(void)
  4361. {
  4362. int l,YY,MM;
  4363. fclose(fpi);
  4364. l = strlen(ifile);
  4365. if (l > 4 && ifile[l-4] == '.' && atoi(ifile+l-3) != 0) // .YYY
  4366. {
  4367. YY = atoi(ifile+l-3) + 1;
  4368. sprintf(ifile+l-3,"%03d",YY);
  4369. }
  4370. else if (l > 5 && ifile[l-5] == '_' && atoi(ifile+l-4) != 0) // _YYYY
  4371. {
  4372. YY = atoi(ifile+l-4) + 1;
  4373. sprintf(ifile+l-4,"%04d",YY);
  4374. }
  4375. else if (l > 7 && ifile[l-7] == '_' && atoi(ifile+l-6) != 0) // _YYYYMM
  4376. {
  4377. MM = atoi(ifile+l-2);
  4378. YY = atoi(ifile+l-6);
  4379. if (MM == 12) YY += 88;
  4380. if (YY > 1) sprintf(ifile+l-6,"%06d",++YY);
  4381. }
  4382. else if (l > 5 && atoi(ifile+l-5) != 0) // "YYYMM" at end
  4383. {
  4384. MM = atoi(ifile+l-2);
  4385. YY = atoi(ifile+l-5);
  4386. if (MM == 12) YY += 88;
  4387. if (YY > 1) sprintf(ifile+l-5,"%05d",++YY);
  4388. }
  4389. else if (l > 4 && atoi(ifile+l-4) != 0) // "YYMM" at end
  4390. {
  4391. MM = atoi(ifile+l-2);
  4392. YY = atoi(ifile+l-4);
  4393. if (MM == 12) YY += 88;
  4394. if (YY > 1) sprintf(ifile+l-4,"%04d",++YY);
  4395. }
  4396. Multi--;
  4397. printf("Continuation File: %s\n",ifile);
  4398. fpi = fopen(ifile,"rb");
  4399. }
  4400. /* ====================================== */
  4401. /* Interpolate gauss grid to regular grid */
  4402. /* ====================================== */
  4403. void Regauss(double *r, double *g, double *Ghi)
  4404. {
  4405. int j,jlon,jlat;
  4406. double np,sp,fn,fs,fe,fw;
  4407. double rphi,rlam,gdx,rdx;
  4408. double *Gam;
  4409. Gam = new double[Gons];
  4410. gdx = 360.0 / Gons;
  4411. rdx = 360.0 / Lons;
  4412. np = sp = 0.0;
  4413. for (jlon = 0 ; jlon < Gons ; ++jlon)
  4414. {
  4415. np += g[jlon];
  4416. sp += g[jlon + DimGG - Gons];
  4417. }
  4418. np /= Gons;
  4419. sp /= Gons;
  4420. for (jlat = 0 ; jlat < Lats ; ++jlat)
  4421. {
  4422. rphi = Outlat->Phi[jlat];
  4423. if (rphi > Ghi[0]) // far north
  4424. {
  4425. fn = (rphi - Ghi[0]) / (90.0 - Ghi[0]);
  4426. fs = 1.0 - fn;
  4427. for (jlon = 0 ; jlon < Gons ; ++jlon)
  4428. Gam[jlon] = fn * np + fs * g[jlon];
  4429. }
  4430. else if (rphi < Ghi[Gats-1]) // far south
  4431. {
  4432. fs = (Ghi[Gats-1] - rphi) / (Ghi[Gats-1] + 90.0);
  4433. fn = 1.0 - fs;
  4434. for (jlon = 0 ; jlon < Gons ; ++jlon)
  4435. Gam[jlon] = fn * g[jlon + DimGG - Gons] + fs * sp;
  4436. }
  4437. else // inside
  4438. {
  4439. j = 0; // search neighboured gauss latitudes
  4440. while (j < Gats-1 && rphi < Ghi[j]) ++j;
  4441. fn = (rphi - Ghi[j]) / (Ghi[j-1] - Ghi[j]);
  4442. fs = 1.0 - fn;
  4443. for (jlon = 0 ; jlon < Gons ; ++jlon)
  4444. Gam[jlon] = fn * g[jlon+(j-1)*Gons] + fs * g[jlon+j*Gons];
  4445. }
  4446. for (jlon = 0 ; jlon < Lons ; ++jlon)
  4447. {
  4448. rlam = jlon * rdx;
  4449. j = (int)floor(rlam / gdx);
  4450. fe = (rlam - j * gdx) / gdx;
  4451. fw = 1.0 - fe;
  4452. if (j >= Gons-1) r[jlon + jlat * Lons] = fw * Gam[j] + fe * Gam[0];
  4453. else r[jlon + jlat * Lons] = fw * Gam[j] + fe * Gam[j+1];
  4454. }
  4455. }
  4456. delete Gam;
  4457. }
  4458. /*******************/
  4459. /* SetOutputHeader */
  4460. /*******************/
  4461. void SetOutputHeader(void)
  4462. {
  4463. int MM,DD,HH;
  4464. if (DPM > 99) // Workaround for months with more than 99 days
  4465. {
  4466. MM = (TermCount / DPM) % 12 + 1;
  4467. HeadOu[2] = OldDate.tm_year * 10000 + MM * 100;
  4468. HeadOu[3] = 0;
  4469. if (!Mean) // Add day & hour info
  4470. {
  4471. HeadOu[2] += (TermCount % DPM) / DayDivisor + 1;
  4472. HeadOu[3] = 100 * (24 / DayDivisor) * ((TermCount % DPM) % DayDivisor);
  4473. }
  4474. }
  4475. else
  4476. {
  4477. HeadOu[2] = OldDate.tm_year * 10000 + OldDate.tm_mon * 100;
  4478. HeadOu[3] = 0;
  4479. if (!Mean)
  4480. {
  4481. HeadOu[2] += OldDate.tm_mday;
  4482. HeadOu[3] = OldDate.tm_hour * 100 + OldDate.tm_min;
  4483. }
  4484. }
  4485. }
  4486. /*****************/
  4487. /* Puma Control */
  4488. /*****************/
  4489. void PumaControl(void)
  4490. {
  4491. int i;
  4492. int LevelOffset;
  4493. int Eof;
  4494. char tb[COLS+2];
  4495. struct tm D1;
  4496. struct tm D2;
  4497. while (1)
  4498. {
  4499. Eof = ReadHeaderRecord();
  4500. if (Eof && Multi)
  4501. {
  4502. SwitchFile();
  4503. if (fpi) Eof = ReadHeaderRecord();
  4504. }
  4505. if (DataStep < 0.01) // Compute time interval
  4506. {
  4507. if (HeadIn[2] != HeadSt[2] || HeadIn[3] != HeadSt[3])
  4508. {
  4509. HeadToDate(HeadSt,&D1);
  4510. HeadToDate(HeadIn,&D2);
  4511. DeltaDy = D2.tm_mday - D1.tm_mday;
  4512. DeltaHr = D2.tm_hour - D1.tm_hour;
  4513. DeltaMn = D2.tm_min - D1.tm_min ;
  4514. if (DeltaDy < 0) DeltaDy = 1; // month changed after 1.st term
  4515. DataStep = DeltaDy + DeltaHr / 24.0 + DeltaMn / 1440.0;
  4516. }
  4517. }
  4518. if ((HeadIn[2] / 100 % 100) > LastMonth && DayDivisor == 0) // Ignore rest of file
  4519. {
  4520. Eof = 1;
  4521. if (Multi)
  4522. {
  4523. SwitchFile();
  4524. if (fpi) Eof = ReadHeaderRecord();
  4525. }
  4526. }
  4527. if (Eof) // Process last read term and finish
  4528. {
  4529. EndOfMonth = TRUE;
  4530. SetOutputHeader();
  4531. PumaProcess();
  4532. PostProcess();
  4533. Dependencies();
  4534. return;
  4535. }
  4536. DecodePumaHeader();
  4537. if (NewMonth < FirstMonth) /* Skip months before FirstMonth */
  4538. {
  4539. SkipPumaArray();
  4540. if (Debug)
  4541. {
  4542. if (RepGrib == REP_SPECTRAL) sprintf(tb,"T%04d",Truncation);
  4543. else sprintf(tb,"N%04d",Lons);
  4544. sprintf(tb+5," SKIPPED Code %3d Level%6d %2.2d.%2.2d.%2.2d %2.2d:%2.2d",
  4545. PumaCode,PumaLevel,NewDate.tm_mday,NewDate.tm_mon,NewDate.tm_year,
  4546. NewDate.tm_hour,NewDate.tm_min);
  4547. LeftText(tb);
  4548. }
  4549. continue;
  4550. }
  4551. if (Debug)
  4552. {
  4553. if (RepGrib == REP_SPECTRAL) sprintf(tb,"T%04d",Truncation);
  4554. else sprintf(tb,"N%04d",Lons);
  4555. sprintf(tb+5," Code %3d Level%6d %2.2d.%2.2d.%2.2d %2.2d:%2.2d",
  4556. PumaCode,PumaLevel,NewDate.tm_mday,NewDate.tm_mon,NewDate.tm_year,
  4557. NewDate.tm_hour,NewDate.tm_min);
  4558. LeftText(tb);
  4559. }
  4560. if (OldMonth > 0)
  4561. {
  4562. EndOfMonth = NewMonth != OldMonth;
  4563. EndOfTerm = memcmp(&NewDate,&OldDate,sizeof(struct tm));
  4564. if (EndOfTerm && MeanCount == DPM-1) EndOfMonth = 1;
  4565. if (EndOfTerm)
  4566. {
  4567. SetOutputHeader();
  4568. PumaProcess();
  4569. PostProcess();
  4570. Dependencies();
  4571. }
  4572. }
  4573. OldDate = NewDate;
  4574. OldMonth = NewMonth;
  4575. if (All[PumaCode].needed)
  4576. {
  4577. if (RepGrib == REP_SPECTRAL) // Spectral array
  4578. {
  4579. if (PumaLevel) All[PumaCode].SetHSpec(SigLevs,OutLevs,FALSE);
  4580. else All[PumaCode].SetHSpec( 1, 1,TRUE );
  4581. if (VerType != 's' || mom[PumaLevel])
  4582. {
  4583. ReadPumaArray(&All[PumaCode].hsp[0]+All[PumaCode].loff);
  4584. All[PumaCode].loff += DimSP;
  4585. }
  4586. else SkipPumaArray();
  4587. }
  4588. else // Gridpoint array
  4589. {
  4590. if (PumaLevel) All[PumaCode].SetHGrid(SigLevs,OutLevs,FALSE);
  4591. else All[PumaCode].SetHGrid( 1, 1,TRUE );
  4592. if (VerType != 's' || mom[PumaLevel])
  4593. {
  4594. if (DimGP == DimGG)
  4595. ReadPumaArray(&All[PumaCode].hgp[0]+All[PumaCode].loff);
  4596. else
  4597. {
  4598. double *ArrayBuffer;
  4599. ArrayBuffer = new double[DimGG];
  4600. ReadPumaArray(ArrayBuffer);
  4601. Regauss(&All[PumaCode].hgp[0]+All[PumaCode].loff,ArrayBuffer,Gaulat->Phi);
  4602. delete ArrayBuffer;
  4603. }
  4604. All[PumaCode].loff += DimGP;
  4605. }
  4606. else SkipPumaArray();
  4607. }
  4608. }
  4609. else SkipPumaArray();
  4610. }
  4611. }
  4612. char *amatch(char *msr, const char *sub)
  4613. {
  4614. int i,nm,ns;
  4615. nm = strlen(msr);
  4616. ns = strlen(sub);
  4617. for (i = 0; i < nm-ns; i++)
  4618. if (strncmp(msr+i,sub,ns) == 0) return (msr+i+ns);
  4619. return NULL;
  4620. }
  4621. int scanpar(const char *name, int def)
  4622. {
  4623. char *cp;
  4624. int value;
  4625. char tb[COLS+2];
  4626. cp = amatch(namelist,name);
  4627. if (cp == NULL)
  4628. {
  4629. value = def;
  4630. sprintf(tb,"%10.10s = %8d (default)",name,value);
  4631. }
  4632. else
  4633. {
  4634. value = atoi(cp);
  4635. sprintf(tb,"%10.10s = %8d ",name,value);
  4636. }
  4637. LeftText(tb);
  4638. return value;
  4639. }
  4640. double scanreal(const char *name, double def)
  4641. {
  4642. char *cp;
  4643. double value;
  4644. char tb[COLS+2];
  4645. cp = amatch(namelist,name);
  4646. if (cp == NULL)
  4647. {
  4648. value = def;
  4649. sprintf(tb,"%10.10s = %8.3f (default)",name,value);
  4650. }
  4651. else
  4652. {
  4653. value = strtod(cp,NULL);
  4654. sprintf(tb,"%10.10s = %8.3f ",name,value);
  4655. }
  4656. LeftText(tb);
  4657. return value;
  4658. }
  4659. char scantex(const char *name, const char choice[])
  4660. {
  4661. char *cp;
  4662. char value;
  4663. int i;
  4664. char tb[COLS+2];
  4665. value = choice[0];
  4666. cp = amatch(namelist,name);
  4667. if (cp)
  4668. {
  4669. while (isspace(*cp)) ++cp;
  4670. for (i=1 ; i < strlen(choice) ; ++i)
  4671. {
  4672. if (*cp == choice[i]) value = *cp;
  4673. }
  4674. }
  4675. sprintf(tb,"%10.10s = %c ",name,value);
  4676. LeftText(tb);
  4677. return value;
  4678. }
  4679. void scantime(void)
  4680. {
  4681. char *cp,*icp;
  4682. int time,i;
  4683. char tb[512];
  4684. nrqh = 0;
  4685. cp = amatch(namelist,"timesel");
  4686. if (cp == NULL)
  4687. {
  4688. hours[nrqh++] = -1;
  4689. sprintf(tb,"%10.10s = all ","timesel");
  4690. LeftText(tb);
  4691. return;
  4692. }
  4693. time = strtol(cp,&icp,10);
  4694. while ((char *)icp != (char *)cp && nrqh < MAX_HOURS) {
  4695. hours[nrqh++] = time;
  4696. cp = icp;
  4697. time = strtol(cp,&icp,10);
  4698. }
  4699. sprintf(tb,"%10.10s = ","timesel");
  4700. for (time = 0 ; time < nrqh ; ++time)
  4701. {
  4702. i = strlen(tb);
  4703. sprintf(tb+i," %02d",hours[time]);
  4704. }
  4705. LeftText(tb);
  4706. }
  4707. void PrintCodes(void)
  4708. {
  4709. int code;
  4710. char tb[COLS+2];
  4711. DashLine();
  4712. CenterText("Code Id Name Units ");
  4713. DashLine();
  4714. for (code=0 ; code < MAXCODES ; ++code) if (strncmp(All[code].Na,"Code",4))
  4715. {
  4716. sprintf(tb,"%4d %-8.8s %-32.32s %-16.16s",code,All[code].Id,All[code].Na,All[code].Un);
  4717. CenterText(tb);
  4718. }
  4719. }
  4720. int CodeOrName(char *a, char **b)
  4721. {
  4722. int l,code;
  4723. while (*a == ' ') ++a;
  4724. if (*a == '+' || *a == '-' || (*a >= '0' && *a <='9'))
  4725. return strtol(a,b,10);
  4726. for (code = 0 ; code < CODES ; ++code)
  4727. {
  4728. l = strlen(All[code].Id);
  4729. if (!strncmp(All[code].Id,a,l) && *(a+l) == ' ')
  4730. {
  4731. *b = a+l;
  4732. return code;
  4733. }
  4734. }
  4735. return 0;
  4736. }
  4737. void scancode(void)
  4738. {
  4739. char *cp,*icp;
  4740. int code;
  4741. char tb[COLS+2];
  4742. cp = amatch(namelist,"code");
  4743. if (cp == NULL) Abort(" *** No code selected for output ***");
  4744. code = CodeOrName(cp,&icp);
  4745. DashLine();
  4746. while (code > 0 && code < CODES)
  4747. {
  4748. sprintf(tb,"Code %5d = %-6.6s %-24.24s",code,All[code].Id,All[code].Na);
  4749. LeftText(tb);
  4750. All[code].selected = 1;
  4751. cp = icp;
  4752. code = CodeOrName(cp,&icp);
  4753. }
  4754. }
  4755. void scanmol(void)
  4756. {
  4757. char *cp,*icp;
  4758. int lev;
  4759. nrml = 0;
  4760. cp = amatch(namelist,"modlev");
  4761. if (cp == NULL) return;
  4762. lev = strtol(cp,&icp,10);
  4763. while (lev > 0 && nrml < MAX_LEVELS)
  4764. {
  4765. mol[nrml++] = lev;
  4766. mom[lev] = 1;
  4767. cp = icp;
  4768. lev = strtol(cp,&icp,10);
  4769. }
  4770. }
  4771. void scanhPa(void)
  4772. {
  4773. char *cp,*icp;
  4774. double lev;
  4775. nrpl = 0;
  4776. cp = amatch(namelist,"hpa");
  4777. if (!cp) return;
  4778. lev = strtod(cp,&icp);
  4779. while (lev > 0 && nrpl < MAX_LEVELS)
  4780. {
  4781. hPa[nrpl++] = lev;
  4782. cp = icp;
  4783. lev = strtod(cp,&icp);
  4784. }
  4785. }
  4786. void scanattributes(void)
  4787. {
  4788. char *cp;
  4789. int i;
  4790. nattr = 0;
  4791. cp = amatch(namelist,"attributes");
  4792. if (!cp) return;
  4793. while (nattr < ATTR_MAX)
  4794. {
  4795. i = 0;
  4796. while (*cp == ':' || isspace(*cp)) ++cp;
  4797. while ((isalnum(*cp) || *cp == '_') && i < 80) AttrNam[nattr][i++] = *cp++;
  4798. while (isspace(*cp)) ++cp;
  4799. if (*cp != '=') break;
  4800. else ++cp;
  4801. while (isspace(*cp)) ++cp;
  4802. if (*cp != '"') break;
  4803. else ++cp;
  4804. i = 0;
  4805. while (*cp != '"' && i < 80) AttrVal[nattr][i++] = *cp++;
  4806. ++cp;
  4807. while (isspace(*cp)) ++cp;
  4808. if (*cp != ';') break;
  4809. ++cp;
  4810. ++nattr;
  4811. }
  4812. }
  4813. void InitAll(void)
  4814. {
  4815. char Id[MAX_ID_LEN];
  4816. char Na[MAX_NA_LEN];
  4817. for (int code = 0 ; code < MAXCODES ; ++code)
  4818. {
  4819. sprintf(Id,"var%3.3d",code);
  4820. sprintf(Na,"Code[%d]",code);
  4821. All[code].Init(Id,Na,"1",0);
  4822. All[code].code = code;
  4823. }
  4824. All[110].Init("mld" ,"mixed_layer_depth" ,"m" ,1); // Not standard
  4825. All[129].Init("sg" ,"surface_geopotential" ,"m2 s-2" ,1);
  4826. All[130].Init("ta" ,"air_temperature" ,"K" ,0);
  4827. All[131].Init("ua" ,"eastward_wind" ,"m s-1" ,0);
  4828. All[132].Init("va" ,"northward_wind" ,"m s-1" ,0);
  4829. All[133].Init("hus" ,"specific_humidity" ,"1" ,0);
  4830. All[134].Init("ps" ,"surface_air_pressure" ,"hPa" ,1);
  4831. All[135].Init("wap" ,"vertical_air_velocity" ,"Pa s-1" ,0); // shortened
  4832. All[137].Init("wa" ,"upward_wind" ,"m s-1" ,0); // Not standard
  4833. All[138].Init("zeta" ,"atm_relative_vorticity" ,"s-1" ,0);
  4834. All[139].Init("ts" ,"surface_temperature" ,"K" ,1);
  4835. All[140].Init("mrso" ,"lwe_of_soil_moisture_content" ,"m" ,1); // shortened
  4836. All[141].Init("snd" ,"surface_snow_thickness" ,"m" ,1);
  4837. All[142].Init("prl" ,"lwe_of_large_scale_precipitation","m s-1" ,1); // rate !!
  4838. All[143].Init("prc" ,"convective_precipitation_rate" ,"m s-1" ,1);
  4839. All[144].Init("prsn" ,"lwe_of_snowfall_amount" ,"m s-1" ,1); // rate !!
  4840. All[145].Init("bld" ,"dissipation_in_atmosphere_bl" ,"W m-2" ,1); // shortened
  4841. All[146].Init("hfss" ,"surface_sensible_heat_flux" ,"W m-2" ,1); // shortened
  4842. All[147].Init("hfls" ,"surface_latent_heat_flux" ,"W m-2" ,1); // shortened
  4843. All[148].Init("stf" ,"streamfunction" ,"m2 s-2" ,0); // Not standard
  4844. All[149].Init("psi" ,"velocity_potential" ,"m2 s-2" ,0); // Not standard
  4845. All[151].Init("psl" ,"air_pressure_at_sea_level" ,"hPa" ,1);
  4846. All[152].Init("pl" ,"log_surface_pressure" ,"1" ,1);
  4847. All[155].Init("d" ,"divergence_of_wind" ,"s-1" ,0);
  4848. All[156].Init("zg" ,"geopotential_height" ,"m" ,0);
  4849. All[157].Init("hur" ,"relative_humidity" ,"1" ,0);
  4850. All[158].Init("tps" ,"tendency_of_surface_air_pressure","Pa s-1" ,1);
  4851. All[159].Init("u3" ,"ustar" ,"m3 s-3" ,1); // Not standard
  4852. All[160].Init("mrro" ,"surface_runoff" ,"m s-1" ,1); // Not standard
  4853. All[161].Init("clw" ,"liquid_water_content" ,"1" ,0); // Not standard
  4854. All[162].Init("cl" ,"cloud_area_fraction_in_layer" ,"1" ,0); // Not standard
  4855. All[163].Init("tcc" ,"total_cloud_cover" ,"1" ,1); // Not standard
  4856. All[164].Init("clt" ,"cloud_area_fraction" ,"1" ,1);
  4857. All[165].Init("uas" ,"eastward_wind_10m" ,"m s-1" ,1); // shortened
  4858. All[166].Init("vas" ,"northward_wind_10m" ,"m s-1" ,1); // shortened
  4859. All[167].Init("tas" ,"air_temperature_2m" ,"K" ,1); // shortened
  4860. All[168].Init("td2m" ,"dew_point_temperature_2m" ,"K" ,1); // shortened
  4861. All[169].Init("tsa" ,"surface_temperature_accumulated" ,"K" ,1); // Not standard
  4862. All[170].Init("tsod" ,"deep_soil_temperature" ,"K" ,1);
  4863. All[171].Init("dsw" ,"deep_soil_wetness" ,"1" ,1);
  4864. All[172].Init("lsm" ,"land_binary_mask" ,"1" ,1);
  4865. All[173].Init("z0" ,"surface_roughness_length" ,"m" ,1);
  4866. All[174].Init("alb" ,"surface_albedo" ,"1" ,1); // Not standard
  4867. All[175].Init("as" ,"surface_albedo" ,"1" ,1); // Not standard
  4868. All[176].Init("rss" ,"surface_net_shortwave_flux" ,"W m-2" ,1); // shortened
  4869. All[177].Init("rls" ,"surface_net_longwave_flux" ,"W m-2" ,1); // shortened
  4870. All[178].Init("rst" ,"toa_net_shortwave_flux" ,"W m-2" ,1); // shortened
  4871. All[179].Init("rlut" ,"toa_net_longwave_flux" ,"W m-2" ,1); // shortened
  4872. All[180].Init("tauu" ,"surface_eastward_stress" ,"Pa" ,1); // shortened
  4873. All[181].Init("tauv" ,"surface_northward_stress" ,"Pa" ,1); // shortened
  4874. All[182].Init("evap" ,"lwe_of_water_evaporation" ,"m s-1" ,1); // rate !!
  4875. All[183].Init("tso" ,"climate_deep_soil_temperature" ,"K" ,1); // Not standard
  4876. All[184].Init("wsoi" ,"climate_deep_soil_wetness" ,"1" ,1);
  4877. All[199].Init("vegc" ,"vegetation_cover" ,"1" ,1); // Not standard
  4878. All[201].Init("tasmax" ,"maximum_air_temperature_2m" ,"K" ,1); // Not standard
  4879. All[202].Init("tasmin" ,"minimum_air_temperature_2m" ,"K" ,1); // Not standard
  4880. All[203].Init("rsut" ,"toa_outgoing_shortwave_flux" ,"W m-2" ,1); // Not standard
  4881. All[204].Init("ssru" ,"surface_solar_radiation_upward" ,"W m-2" ,1); // Not standard
  4882. All[205].Init("stru" ,"surface_thermal_radiation_upward","W m-2" ,1); // Not standard
  4883. All[207].Init("tso2" ,"soil_temperature_level_2" ,"K" ,1); // Not standard
  4884. All[208].Init("tso3" ,"soil_temperature_level_3" ,"K" ,1); // Not standard
  4885. All[209].Init("tso4" ,"soil_temperature_level_4" ,"K" ,1); // Not standard
  4886. All[210].Init("sic" ,"sea_ice_cover" ,"1" ,1); // Not standard
  4887. All[211].Init("sit" ,"sea_ice_thickness" ,"m" ,1); // Not standard
  4888. All[212].Init("vegf" ,"forest_cover" ,"1" ,1); // Not standard
  4889. All[218].Init("snm" ,"snow_melt" ,"m s-1" ,1); // Not standard
  4890. All[221].Init("sndc" ,"snow_depth_change" ,"m s-1" ,1); // Not standard
  4891. All[230].Init("prw" ,"atmosphere_water_vapor_content" ,"kg m-2" ,1); // Not standard
  4892. All[232].Init("glac" ,"glacier_cover" ,"1" ,1); // Not standard
  4893. All[238].Init("tsn" ,"snow_temperature" ,"K" ,1);
  4894. All[259].Init("spd" ,"wind_speed" ,"m s-1" ,0); // Not standard
  4895. All[260].Init("pr" ,"total_precipitation" ,"m s-1" ,1); // Not standard
  4896. All[261].Init("ntr" ,"net_top_radiation" ,"W m-2" ,1); // Not standard
  4897. All[262].Init("nbr" ,"net_bottom_radiation" ,"W m-2" ,1); // Not standard
  4898. All[263].Init("hfns" ,"surface_downward_heat_flux" ,"W m-2" ,1); // shortened
  4899. All[264].Init("wfn" ,"net_water_flux" ,"m s-1" ,1); // Not standard
  4900. All[273].Init("dpdx" ,"d(ps)/dx" ,"Pa m-1" ,1); // Not standard
  4901. All[274].Init("dpdy" ,"d(ps)/dy" ,"Pa m-1" ,1); // Not standard
  4902. All[277].Init("hlpr" ,"half_level_pressure" ,"Pa" ,0); // Not standard
  4903. All[278].Init("flpr" ,"full_level_pressure" ,"Pa" ,0); // Not standard
  4904. }
  4905. void Usage(void)
  4906. {
  4907. char Line[132];
  4908. fpi = fopen("/usr/local/doc/burn7.txt","r");
  4909. if (fpi)
  4910. do
  4911. {
  4912. fgets(Line,130,fpi);
  4913. printf("%s",Line);
  4914. }
  4915. while (!feof(fpi) && Line[0] != '#');
  4916. if (fpi) fclose(fpi);
  4917. printf("\nburn7 [options] InputFile OutputFile <namelist >printout\n");
  4918. printf(" option -h : help (this output)\n");
  4919. printf(" option -c : print available codes and names\n");
  4920. printf(" option -d : debug mode (verbose output)\n");
  4921. printf(" option -m : Mean=1 output (override namelist option)\n");
  4922. printf(" option -n : NetCDF output (override namelist option)\n");
  4923. printf(" option -s : Save memory (increases CPU time)\n");
  4924. printf(" InputFile : PUMA or PlaSim data file\n");
  4925. #ifdef NETCDF_OUTPUT
  4926. printf(" <OutputFile> : SERVICE, or NetCDF format file\n");
  4927. #else
  4928. printf(" <OutputFile> : SERVICE format file\n");
  4929. #endif
  4930. printf(" namelist is read from <stdin>\n");
  4931. printf(" printout is written to <stdout>\n\n");
  4932. exit(1);
  4933. }
  4934. void parini(void)
  4935. {
  4936. char c;
  4937. unsigned int i;
  4938. int jind;
  4939. int lc;
  4940. char tb[COLS+2];
  4941. i = 1;
  4942. namelist[0] = ' ';
  4943. lc = 1;
  4944. c = getchar();
  4945. while (!feof(stdin) && i < MAX_NL)
  4946. {
  4947. if (c == ':' ) lc = 0; // No conversion to lower case
  4948. if (c == '\n') lc = 1;
  4949. if (c == '#') // Skip comment
  4950. {
  4951. while (!feof(stdin) && c != '\n') c = getchar();
  4952. }
  4953. if (lc)
  4954. {
  4955. if ((c >= '0' && c <= '9') ||
  4956. c == '-' || c == '.') namelist[i++] = c;
  4957. else if (c >= 'a' && c <= 'z') namelist[i++] = c;
  4958. else if (c >= 'A' && c <= 'Z') namelist[i++] = tolower(c);
  4959. else c = ' ';
  4960. if (c == ' ' && namelist[i-1] != ' ') namelist[i++] = c;
  4961. }
  4962. else namelist[i++] = c;
  4963. c = getchar();
  4964. }
  4965. namelist[i++] = ' ';
  4966. namelist[i] = 0;
  4967. if (Debug)
  4968. {
  4969. sprintf(tb,"Length of namelist: %d bytes",(int)strlen(namelist));
  4970. LeftText(tb);
  4971. for (i = 0; i<strlen(namelist); i+=40)
  4972. {
  4973. sprintf(tb,"namelist[%02d]=%-40.40s",i,namelist+i);
  4974. LeftText(tb);
  4975. }
  4976. StarLine();
  4977. }
  4978. Lats = scanpar("lats",Lats);
  4979. Lons = scanpar("lons",Lons);
  4980. DPM = scanpar("dpm",0);
  4981. if (DPM > 99 && DPM < 2400) /* Days Per Month */
  4982. {
  4983. DayDivisor = DPM / 100 + 1;
  4984. while (24 % DayDivisor && DayDivisor < 24) ++DayDivisor;
  4985. sprintf(tb,"%10.10s = %8d ","daydivisor",DayDivisor);
  4986. LeftText(tb);
  4987. }
  4988. DPY = scanpar("dpy",0);
  4989. if (DPY > 0) DaysPerYear = DPY;
  4990. Cyclical = scanpar("cyclical",Cyclical);
  4991. if (Cyclical) Cyclical = 1;
  4992. if (VerType == 0 || HorType == 0)
  4993. {
  4994. VerType = scantex("vtype" ,"ps"); // 1. char is default value (p)
  4995. HorType = scantex("htype" ,"gsfz"); // 1. char is default value (g)
  4996. }
  4997. Multi = scanpar("multi" ,0);
  4998. LevelFactor = scanreal("levelfactor",1.0);
  4999. if (NetCDF == 0) NetCDF = scanpar("netcdf",0);
  5000. HeadOu[6] = scanpar("head7",0);
  5001. mars = scanpar("mars" ,0);
  5002. FirstMonth = scanpar("first",1);
  5003. LastMonth = scanpar("last",12);
  5004. PlanetRadius = scanreal("radius",EARTH_RADIUS);
  5005. Grav = scanreal("gravity",EARTH_GRAV);
  5006. SigmaTop = scanreal("sigmatop",0.0);
  5007. vct[SigLevs] = SigmaTop;
  5008. if (FirstMonth < 1) FirstMonth = 1;
  5009. if (LastMonth > 12) LastMonth = 12;
  5010. if (LastMonth < FirstMonth) LastMonth = FirstMonth;
  5011. if (VerType == 's')
  5012. {
  5013. switch (HorType)
  5014. {
  5015. case 's': OutRep = HYB_SPEC; break;
  5016. case 'f': OutRep = HYB_FOUR; break;
  5017. case 'z': OutRep = HYB_ZONM; break;
  5018. case 'g': OutRep = HYB_GRID; break;
  5019. }
  5020. }
  5021. if (VerType == 'p')
  5022. {
  5023. switch (HorType)
  5024. {
  5025. case 's': OutRep = PRE_SPEC; break;
  5026. case 'f': OutRep = PRE_FOUR; break;
  5027. case 'z': OutRep = PRE_ZONM; break;
  5028. case 'g': OutRep = PRE_GRID; break;
  5029. }
  5030. }
  5031. if (Mean == 0) Mean = scanpar("mean" ,1);
  5032. if (Mean && OutRep < HYB_GRID)
  5033. {
  5034. sprintf(tb," mean = 1 ignored for spectral data on sigma levels");
  5035. LeftText(tb);
  5036. Mean = 0;
  5037. }
  5038. if (Multi) --Multi;
  5039. if (mars) {
  5040. Grav = MARS_GRAV;
  5041. PlanetRadius = MARS_RADIUS;
  5042. RD = MARS_RD;
  5043. }
  5044. scantime();
  5045. scancode();
  5046. DashLine();
  5047. if (VerType == 's') /* model levels */
  5048. {
  5049. scanmol();
  5050. mom[0] = 1; // surface arrays are selected always
  5051. if (nrml) /* Sigma levels explicitely given */
  5052. {
  5053. nrml = 0;
  5054. for (i=1 ; i <= SigLevs ; ++i)
  5055. {
  5056. if (mom[i])
  5057. {
  5058. level[nrml] = mol[nrml] = i;
  5059. nrml++;
  5060. }
  5061. }
  5062. SigLevs = OutLevs = nrml;
  5063. }
  5064. else /* No sigma levels specified -> select all */
  5065. {
  5066. OutLevs = nrml = SigLevs;
  5067. for (i=0 ; i < OutLevs ; ++i)
  5068. {
  5069. level[i] = mol[i] = mom[i+1] = i+1;
  5070. }
  5071. }
  5072. for (i=0 ; i < OutLevs ; ++i)
  5073. {
  5074. jind = mol[i] - 1;
  5075. LevelUnits[i] = mol[i];
  5076. SigmaF[i] = (int)(500000.0 * (vct[jind+1] - vct[jind])); // sigma * 1E6
  5077. sprintf(tb,"Level %4d = %10.6f",i+1,
  5078. 0.5 * (vct[SigLevs+mol[i]]+vct[SigLevs+mol[i]+1]));
  5079. LeftText(tb);
  5080. }
  5081. }
  5082. else /* pressure levels */
  5083. {
  5084. scanhPa();
  5085. if (nrpl)
  5086. {
  5087. OutLevs = nrpl;
  5088. for (i=0 ; i < OutLevs ; ++i)
  5089. {
  5090. level[i] = 100.0 * hPa[i];
  5091. if (hPa[i] < 0.0) Abort("pressure level < 0.0 is illegal");
  5092. // if (hPa[i] > 2000.0) Abort("pressure level > 2000 hPa is illegal");
  5093. }
  5094. }
  5095. else
  5096. {
  5097. OutLevs = nrpl = 10;
  5098. for (i=0 ; i < OutLevs ; ++i)
  5099. {
  5100. hPa[i] = (i+1) * 100.0;
  5101. level[i] = 100.0 * hPa[i];
  5102. }
  5103. }
  5104. for (i=0 ; i < OutLevs ; ++i)
  5105. {
  5106. LevelUnits[i] = (int)(LevelFactor * 100.0 * hPa[i] + 0.5);
  5107. sprintf(tb,"Level %4d = %14.4f hPa",i+1,hPa[i]);
  5108. LeftText(tb);
  5109. }
  5110. }
  5111. DashLine();
  5112. scanattributes();
  5113. for (i=0 ; i < nattr ; ++i)
  5114. {
  5115. sprintf(tb,"NetCDF attribute[%2d] :%s = \"%s\" ;",
  5116. i,AttrNam[i],AttrVal[i]);
  5117. LeftText(tb);
  5118. }
  5119. }
  5120. void dimcalc(void)
  5121. {
  5122. PolyDisk = Lats == 2048; // Currently T1365 only
  5123. Waves = Truncation + 1;
  5124. Fouriers = Waves * 2;
  5125. DimSP = (Truncation + 1) * (Truncation + 2);
  5126. DimFC = Lats * Fouriers;
  5127. DimGP = Lats * Lons;
  5128. DimGG = Gats * Gons;
  5129. Dim3GP = SigLevs * DimGP;
  5130. Dim3GG = SigLevs * DimGG;
  5131. Dim3FC = SigLevs * DimFC;
  5132. Dim3SP = SigLevs * DimSP;
  5133. DimSP_half = DimSP / 2;
  5134. DimAB = MAX(DimGG,DimGP) + MAX(Lons,Gons);
  5135. DashLine();
  5136. if (VerType == 's') LeftText("Vertical Type = Sigma [S]");
  5137. if (VerType == 'p') LeftText("Vertical Type = Pressure [P]");
  5138. if (HorType == 's') LeftText("Horizontal Type = Spherical Harmonics [S]");
  5139. if (HorType == 'f') LeftText("Horizontal Type = Fourier Coefficients [F]");
  5140. if (HorType == 'z') LeftText("Horizontal Type = Zonal Means [Z]");
  5141. if (HorType == 'g')
  5142. {
  5143. if (Lons == Gons && Lats == Gats)
  5144. {
  5145. LeftText("Horizontal Type = Gaussian Grid [G]");
  5146. GaussianOutput = 1;
  5147. }
  5148. else
  5149. {
  5150. LeftText("Horizontal Type = Grid (Lons x Lats) [G]");
  5151. GaussianOutput = 0;
  5152. }
  5153. }
  5154. DashLine();
  5155. Record_double = new double[DimAB];
  5156. Record_float = (float *)Record_double;
  5157. Record_int = (int *)Record_double;
  5158. Record_short = (unsigned short *)Record_double;
  5159. Record_char = (char *)Record_double;
  5160. CosPhi = new double[Lats];
  5161. RevCosPhi = new double[Lats];
  5162. DerivationFactor = new double[Lats];
  5163. }
  5164. /* ------------------------------------------------------ */
  5165. /* Check file OutRep and decode level number and truncation */
  5166. /* ------------------------------------------------------ */
  5167. void AnalyzeFile(void)
  5168. {
  5169. int i;
  5170. LONG fcb,fce; /* Fortran Record Control Words */
  5171. char Id[8];
  5172. char tb[COLS+2];
  5173. union EndianCheck
  5174. {
  5175. char b[sizeof(int)];
  5176. int i;
  5177. } ec;
  5178. ec.i = 8;
  5179. CoreBigEndian = ec.b[0] == 0;
  5180. fread(Id,1,8,fpi); // Read first 8 bytes
  5181. FileBigEndian = Id[0] == 0;
  5182. Endian = CoreBigEndian != FileBigEndian;
  5183. if (FileBigEndian)
  5184. {
  5185. if (Id[3] == 0) LongFCW = 1;
  5186. }
  5187. else
  5188. {
  5189. if (Id[4] == 0) LongFCW = 1;
  5190. }
  5191. rewind(fpi);
  5192. HeadSize = fcb = ReadFCW();
  5193. if (fcb != 8 && fcb != 32 && fcb != 64) Abort("Not a PUMA/PLASIM file");
  5194. CenterText("Found PUMA/Planet Simulator data set");
  5195. if (CoreBigEndian) CenterText("Running on BIG endian machine");
  5196. else CenterText("Running on little endian machine");
  5197. if (FileBigEndian) CenterText("File is in BIG endian format");
  5198. else CenterText("File is in little endian format");
  5199. if (Endian) CenterText("Endian swap activated");
  5200. if (LongFCW) CenterText("Record control words have 64 bits");
  5201. else CenterText("Record control words have 32 bits");
  5202. if (fcb == 8) CenterText("Header format: PUMA-II ");
  5203. if (fcb == 32) CenterText("Header format: Service 32 bit");
  5204. if (fcb == 64) CenterText("Header format: Service 64 bit");
  5205. BlankLine();
  5206. if (fcb == 8)
  5207. {
  5208. HeadSize = 32;
  5209. i = fread(Id,1,8,fpi);
  5210. if (strncmp(Id,"PUMA-II ",8)) Abort("PUMA-II header missing");
  5211. fce = ReadFCW();
  5212. if (check_fcw(fcb,fce)) Abort("Wrong FORTRAN control word after PUMA header");
  5213. Truncation = ReadINTRecord();
  5214. Gats = ReadINTRecord();
  5215. AllLevs = SigLevs = ReadINTRecord();
  5216. if (SigLevs < 1 || SigLevs > 1000) Abort("Illegal value for Level");
  5217. SingleLevel = (SigLevs == 1);
  5218. nvct = 2 * SigLevs + 2;
  5219. /* Check length of sigma vector and determine precision */
  5220. fcb = ReadFCW();
  5221. RealSize = fcb / SigLevs; // Should be float (4) or double (8)
  5222. if (RealSize != sizeof(float) && RealSize != sizeof(double))
  5223. Abort("FCW error on level record");
  5224. for (i = 0 ; i < SigLevs ; i++)
  5225. {
  5226. if (RealSize == sizeof(float)) vct[i+SigLevs+2] = ReadFLOAT();
  5227. else vct[i+SigLevs+2] = ReadDOUBLE();
  5228. }
  5229. fce = ReadFCW();
  5230. if (check_fcw(fcb,fce)) Abort("FCW mismatch on level record");
  5231. /* Header = "PUMA-II " Truncation Lats SigLevs sigmah */
  5232. /* 2-FCW FCW-1-FCW FCW-1-FCW FCW-1-FCW FCW-SigLevs-FCW */
  5233. HeaderWords = SigLevs * RealSize / 4 + 5 + 9 * (1 + LongFCW);
  5234. ReadHeaderRecord();
  5235. if (HeadIn[7] > 100) DaysPerYear = HeadIn[7];
  5236. }
  5237. else
  5238. {
  5239. rewind(fpi);
  5240. ReadHeaderRecord();
  5241. if (HeadIn[0] != 333) Abort("Initial code 333 was not found");
  5242. Gats = HeadIn[5];
  5243. AllLevs = SigLevs = HeadIn[6];
  5244. SingleLevel = (SigLevs == 1);
  5245. nvct = 2 * SigLevs + 2;
  5246. Truncation = HeadIn[7];
  5247. /* Check length of array and determine precision */
  5248. fcb = ReadFCW();
  5249. RealSize = fcb / (Gats * Gats * 2); // Should be float (4) or double (8)
  5250. fseek(fpi,-4*LongFCW,SEEK_CUR);
  5251. if (RealSize != sizeof(float) && RealSize != sizeof(double))
  5252. Abort("FCW error on first array");
  5253. for (i = 0 ; i < SigLevs ; i++)
  5254. {
  5255. if (RealSize == sizeof(float)) vct[i+SigLevs+2] = ReadFLOAT();
  5256. else vct[i+SigLevs+2] = ReadDOUBLE();
  5257. }
  5258. if (RealSize == sizeof(float)) DaysPerYear = ReadFLOAT();
  5259. else DaysPerYear = ReadDOUBLE();
  5260. }
  5261. HeadSt = HeadIn;
  5262. sprintf(tb,"Truncation = %6d",Truncation);
  5263. CenterText(tb);
  5264. sprintf(tb,"Latitudes = %6d",Gats);
  5265. CenterText(tb);
  5266. sprintf(tb,"Longitudes = %6d",Gats*2);
  5267. CenterText(tb);
  5268. sprintf(tb,"Sigma Levels = %6d",SigLevs);
  5269. CenterText(tb);
  5270. if (RealSize == 8)
  5271. sprintf(tb,"Double precision data: Bytes = %6d",RealSize);
  5272. else if (RealSize == 4)
  5273. sprintf(tb,"Single precision data: Bytes = %6d",RealSize);
  5274. else
  5275. sprintf(tb,"Size of real data = %6d",RealSize);
  5276. CenterText(tb);
  5277. BlankLine();
  5278. sprintf(tb,"Half Level [p] [sigma]");
  5279. CenterText(tb);
  5280. for (i = 0; i<nvct/2; i++)
  5281. {
  5282. sprintf(tb,"%10.1f %14.4f %14.4f",(float)i,vct[i],vct[i+nvct/2]);
  5283. CenterText(tb);
  5284. }
  5285. StarLine();
  5286. rewind(fpi);
  5287. }
  5288. const char *MoName[13] = {"Nix","Jan","Feb","Mar","Apr","May","Jun",
  5289. "Jul","Aug","Sep","Oct","Nov","Dec"};
  5290. void WriteGradsCtl()
  5291. {
  5292. int i,j,yy,mm,dd,code,varcodes;
  5293. FILE *fp;
  5294. double DelLon;
  5295. fp = fopen(gfile,"w");
  5296. if (HorType == 'z')
  5297. fprintf(fp,"DSET ^%s\n",rfile);
  5298. else
  5299. fprintf(fp,"DSET ^%s\n",ofile);
  5300. fprintf(fp,"UNDEF 9e09i\n");
  5301. if (HorType == 'z')
  5302. fprintf(fp,"XDEF 1 LINEAR 0 1\n");
  5303. else
  5304. {
  5305. DelLon = 360.0 / Gons;
  5306. fprintf(fp,"XDEF %5d LINEAR 0.0 %14.8f\n",Gons,DelLon);
  5307. }
  5308. fprintf(fp,"OPTIONS YREV\n");
  5309. fprintf(fp,"YDEF %5d LEVELS\n",Gats);
  5310. for (j=Gats-1 ; j >= 0 ; j-=8)
  5311. {
  5312. for (i=j ; i >= 0 && i> j-8 ; --i)
  5313. fprintf(fp,"%14.8f",Outlat->Phi[i]);
  5314. fprintf(fp,"\n");
  5315. }
  5316. if (HorType != 'z')
  5317. {
  5318. fprintf(fp,"OPTIONS SEQUENTIAL\n");
  5319. fprintf(fp,"XYHEADER %d\n",40 + 8 * LongFCW);
  5320. }
  5321. if (OutLevs < 2)
  5322. {
  5323. if (VerType == 'p') fprintf(fp,"ZDEF 1 LINEAR %14.8f 1\n",hPa[0]);
  5324. else fprintf(fp,"ZDEF 1 LINEAR %d 1\n",mol[0]);
  5325. }
  5326. else
  5327. {
  5328. fprintf(fp,"ZDEF %d LEVELS\n",OutLevs);
  5329. if (VerType == 'p')
  5330. {
  5331. for (j=0 ; j < OutLevs ; j+=8)
  5332. {
  5333. for (i=j ; i < OutLevs && i < j+8 ; ++i)
  5334. if (HorType == 'z' && hPa[0] < hPa[OutLevs-1])
  5335. fprintf(fp,"%14.8f",hPa[OutLevs-1-i]);
  5336. else
  5337. fprintf(fp,"%14.8f",hPa[i]);
  5338. fprintf(fp,"\n");
  5339. }
  5340. if (HorType == 'z' && hPa[0] < hPa[OutLevs-1])
  5341. fprintf(fp,"OPTIONS ZREV\n");
  5342. }
  5343. else
  5344. {
  5345. for (j=0 ; j < OutLevs ; j+=8)
  5346. {
  5347. for (i=j ; i < OutLevs && i < j+8 ; ++i)
  5348. if (HorType == 'z' && mol[0] < mol[OutLevs-1])
  5349. fprintf(fp,"%10d",mol[OutLevs-1-i]);
  5350. else
  5351. fprintf(fp,"%10d",mol[i]);
  5352. fprintf(fp,"\n");
  5353. }
  5354. if (HorType == 'z' && mol[0] < mol[OutLevs-1])
  5355. fprintf(fp,"OPTIONS ZREV\n");
  5356. }
  5357. }
  5358. yy = HeadSt[2] / 10000;
  5359. mm = HeadSt[2] / 100 % 100;
  5360. dd = HeadSt[2] % 100;
  5361. if (Mean)
  5362. fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d 1mo\n",
  5363. MonthCount,dd,MoName[mm],yy);
  5364. else if (DeltaMn > 0)
  5365. fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d %dmn\n",
  5366. TermCount,dd,MoName[mm],yy,DeltaMn);
  5367. else if (DeltaHr > 0)
  5368. fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d %dhr\n",
  5369. TermCount,dd,MoName[mm],yy,DeltaHr);
  5370. else
  5371. fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d %ddy\n",
  5372. TermCount,dd,MoName[mm],yy,DeltaDy);
  5373. varcodes = 0;
  5374. for (code = 0 ; code < CODES ; ++code)
  5375. if (All[code].selected) ++varcodes;
  5376. fprintf(fp,"VARS %d\n",varcodes);
  5377. for (code = 0 ; code < CODES ; ++code)
  5378. if (All[code].selected)
  5379. fprintf(fp,"%s %d 99 %s\n",
  5380. All[code].Id,All[code].plev,All[code].Na);
  5381. fprintf(fp,"ENDVARS\n");
  5382. fclose(fp);
  5383. }
  5384. int main(int argc, char *argv[])
  5385. {
  5386. int i,l;
  5387. int wdim;
  5388. char tb[COLS+2];
  5389. time_t StartTime;
  5390. StartTime = time(NULL);
  5391. /*********************/
  5392. /* print information */
  5393. /*********************/
  5394. StarLine();
  5395. CenterText(V0);
  5396. CenterText(V1);
  5397. DashLine();
  5398. CenterText(V2);
  5399. CenterText(V3);
  5400. CenterText(V4);
  5401. StarLine();
  5402. sprintf(tb,"Run started at %s",ctime(&StartTime));
  5403. strcpy(tb+strlen(tb)-1," local time");
  5404. CenterText(tb);
  5405. StarLine();
  5406. InitAll();
  5407. /***********************/
  5408. /* options & filenames */
  5409. /***********************/
  5410. for (i = 1 ; i < argc ; ++i) {
  5411. if (argv[i][0] == '-') {
  5412. if (argv[i][1] == 'c') {PrintCodes(); exit(1);}
  5413. else if (argv[i][1] == 'd') Debug = 1;
  5414. else if (argv[i][1] == 'v') Debug = 1;
  5415. else if (argv[i][1] == 'n') NetCDF = 1;
  5416. else if (argv[i][1] == 'g') Grads = 1;
  5417. else if (argv[i][1] == 'm') Mean = 1;
  5418. else if (argv[i][1] == 'p') PolyCreate = 1;
  5419. else if (argv[i][1] == 'i') GaussGrid = 1;
  5420. else if (argv[i][1] == 'r') GaussGrid = 0;
  5421. else if (argv[i][1] == 's') SaveMemory = 1;
  5422. else Usage();
  5423. }
  5424. else if (ifile[0] == '\0') strcpy(ifile,argv[i]);
  5425. else if (ofile[0] == '\0') strcpy(ofile,argv[i]);
  5426. else if (strcmp("Debug",argv[i]) == 0) Debug = 1;
  5427. else Usage();
  5428. }
  5429. if (NetCDF) Grads = 0;
  5430. if (ifile[0] == '\0' || ofile[0] == '\0') {
  5431. printf("*** Missing filename ***\n");
  5432. Usage();
  5433. }
  5434. /*******************/
  5435. /* open input file */
  5436. /*******************/
  5437. fpi = fopen(ifile,"rb");
  5438. if (fpi == 0) {
  5439. printf("could not open input file %s\n",ifile);
  5440. exit(1);
  5441. }
  5442. /******************/
  5443. /* pre-processing */
  5444. /******************/
  5445. AnalyzeFile();
  5446. Gons = Gats * 2;
  5447. Lats = Gats;
  5448. Lons = Gons;
  5449. /*******************/
  5450. /* initializations */
  5451. /*******************/
  5452. parini();
  5453. l = strlen(ofile);
  5454. if (NetCDF) // Add ".nc" extension for NetCDF filename if not specified
  5455. {
  5456. if (l < 4 || strcmp(ofile+l-3,".nc")) strcat(ofile,".nc");
  5457. }
  5458. else // Add ".srv" extension for Service format if not specified
  5459. {
  5460. if (l > 4 && !strcmp(ofile+l-4,".srv")) l -= 4;
  5461. ofile[l] = 0;
  5462. strcpy(gfile,ofile);
  5463. strcpy(rfile,ofile);
  5464. strcat(ofile,".srv");
  5465. strcat(gfile,".ctl");
  5466. strcat(rfile,".gra");
  5467. }
  5468. sprintf(tb," Input File: %s",ifile); LeftText(tb);
  5469. sprintf(tb,"Output File: %s",ofile); LeftText(tb);
  5470. if (Grads) {sprintf(tb,"Grads File: %s",gfile); LeftText(tb);}
  5471. if (Grads && HorType == 'z')
  5472. {sprintf(tb,"Grads Data: %s",rfile); LeftText(tb);}
  5473. if (Debug) LeftText("Debug on");
  5474. #ifndef NETCDF_OUTPUT
  5475. if (NetCDF) Abort("This executable was not compiled for NetCDF");
  5476. #endif
  5477. /********************/
  5478. /* open output file */
  5479. /********************/
  5480. if (!NetCDF)
  5481. {
  5482. gp = fopen(ofile,"wb");
  5483. if (gp == 0)
  5484. {
  5485. printf("could not open output file <%s>\n",ofile);
  5486. exit(1);
  5487. }
  5488. }
  5489. dimcalc();
  5490. HybSpec = new ServiceGrid(gp,DimSP,1);
  5491. HybFour = new ServiceGrid(gp,Lats,Fouriers);
  5492. HybGrid = new ServiceGrid(gp,Lons,Lats);
  5493. HybSect = new ServiceSect(gp,Lats,OutLevs);
  5494. /* FFT initialization */
  5495. if (OutLevs <= SigLevs) wdim = (Lons + 3) * Lats * SigLevs;
  5496. else wdim = (Lons + 3) * Lats * OutLevs ;
  5497. wfc = new double[wdim];
  5498. wgp = new double[wdim];
  5499. fft_set(Lons);
  5500. filename = strrchr(ifile,'/');
  5501. if (filename == 0) filename = ifile;
  5502. else filename++ ;
  5503. HeadOu[7] = atol(filename);
  5504. if (VerType == 'p' &&
  5505. (Divergence->selected || VeloPot->selected ||
  5506. Vorticity->selected || StreamF->selected))
  5507. SpecialUV = 1;
  5508. Dependencies();
  5509. // Check correct vertical coordinate
  5510. if (GeopotHeight->selected && VerType != 'p')
  5511. {
  5512. printf("\n ****************** E R R O R ************************\n");
  5513. printf(" * Geopotential height (156) requires pressure level *\n");
  5514. printf(" *****************************************************\n");
  5515. exit(1);
  5516. }
  5517. Geopotential->needed |= OutRep >= PRE_GRID
  5518. || SLP->needed || GeopotHeight->needed;
  5519. if (OutRep) legini();
  5520. if (PolyCreate) exit(0); /* Called for Legendre Polynomials only */
  5521. #ifdef NETCDF_OUTPUT
  5522. if (NetCDF) NetOpen(ofile);
  5523. #endif
  5524. PumaControl();
  5525. if (gp) fclose(gp);
  5526. #ifdef NETCDF_OUTPUT
  5527. if (NetCDF) NetClose();
  5528. #endif
  5529. if (Grads) WriteGradsCtl();
  5530. StarLine();
  5531. if (DaysPerYear < 1) DaysPerYear = 360;
  5532. if (DPM > 99) DaysPerYear = DPM * 12;
  5533. sprintf(tb,"Using %d day calendar",DaysPerYear);
  5534. CenterText(tb);
  5535. sprintf(tb,"Data interval = %6.2f hours",DataStep * 24.0);
  5536. CenterText(tb);
  5537. StarLine();
  5538. {
  5539. double ut,st;
  5540. struct rusage ru;
  5541. getrusage(RUSAGE_SELF,&ru);
  5542. ut = ru.ru_utime.tv_sec + 0.000001 * ru.ru_utime.tv_usec;
  5543. st = ru.ru_stime.tv_sec + 0.000001 * ru.ru_stime.tv_usec;
  5544. sprintf(tb,"User time: %10.3lf seconds",ut);
  5545. LeftText(tb);
  5546. sprintf(tb,"System time: %10.3lf seconds",st);
  5547. LeftText(tb);
  5548. sprintf(tb,"Total time: %10.3lf seconds",ut+st);
  5549. LeftText(tb);
  5550. if (ru.ru_maxrss > 0)
  5551. {
  5552. sprintf(tb,"Memory usage: %10.3lf MBytes",0.000001 * ru.ru_maxrss);
  5553. LeftText(tb);
  5554. }
  5555. if (ru.ru_minflt > 0)
  5556. {
  5557. sprintf(tb,"Page reclaims: %10ld page",ru.ru_minflt);
  5558. if (ru.ru_minflt != 1) strcat(tb,"s");
  5559. LeftText(tb);
  5560. }
  5561. if (ru.ru_majflt > 0)
  5562. {
  5563. sprintf(tb,"Page faults: %10ld page",ru.ru_majflt);
  5564. if (ru.ru_majflt != 1) strcat(tb,"s");
  5565. LeftText(tb);
  5566. }
  5567. if (ru.ru_nswap > 0)
  5568. {
  5569. sprintf(tb,"Swaps : %10ld",ru.ru_nswap);
  5570. LeftText(tb);
  5571. }
  5572. if (ru.ru_inblock > 0)
  5573. {
  5574. sprintf(tb,"Disk read: %10ld block",ru.ru_inblock);
  5575. if (ru.ru_inblock != 1) strcat(tb,"s");
  5576. LeftText(tb);
  5577. }
  5578. if (ru.ru_oublock > 0)
  5579. {
  5580. sprintf(tb,"Disk Write: %10ld block",ru.ru_oublock);
  5581. if (ru.ru_oublock != 1) strcat(tb,"s");
  5582. LeftText(tb);
  5583. }
  5584. StarLine();
  5585. }
  5586. return 0;
  5587. }