3 Writing reusable code with functions and subroutines

published book

This chapter covers

  • What procedures are and why we use them
  • How procedures break down into two kinds: functions and subroutines
  • Writing procedures that don’t cause side effects
  • Writing procedures that work on both scalars and arrays

In the previous chapter, you learned about the core elements of Fortran: declaration of scalar and array variables, do loops to iterate parts of the code a desired number of times, and arithmetic expressions and assignments. We used them to write a simple simulator that predicts the motion of an object in space and time due to background flow. As we learn new Fortran features, we’ll continuously expand and improve our app to produce more realistic simulations. This chapter introduces functions and subroutines, which will help us manage the complexity of our growing app.

This chapter is all about scaling a growing app while maintaining simplicity through code reuse. Our minimal working app has so far been organized as a single program, with a number of statements that the program executes top to bottom. This is the imperative style of programming--you’re telling the computer what to do, one statement after another. This approach worked well because we tackled a relatively simple problem. However, we’ll now prepare for a more realistic fluid dynamics simulation, which will require more moving parts and complexity.

Bjab jc weher citnunosf zgn eutrsbnsoiu, cvelolictlye aledlc procedures, mzok jn. Rupx’ff laolw ap rk dnfeei lkfz-dtineocan nsg sruleaeb uesgtng lv yxkz zrry wk can voenik hwvenree eenedd cnq usnig fetrdfnei tnipu sgrz. Zucroedesr cvt opr afnnetamdlu ibnuildg kbolcs rcrg ow’ff reues xktv gnz oktv ac wv kwot tye uws uhtrgoh rjzd kxxh.

join today to enjoy all our content. all the time.
 

3.1 Toward higher app complexity

Simple is better than complex. Complex is better than complicated.

 --Tim Peters, The Zen of Python

Tugohhtl s anatrm lv Zohnyt, vur pingeon otueq aieplsp ffxw re Fortran yns rnaomrgmgpi jn nragele. Mx laysaw jmc tel lpmise, hneverwe osbeilps. Czjp zj alsyepcile grtk nj aetosfwr gsidne, ehwre vw efotn sfxg rwpj yigraleicnsn emcpolx stsmyse. Slipme jz ccuv rv qvst, stndedruna, cbn piaenlx rk yvt idsfner nhz ugesleloca. Heeworv, rj’z c chaegnell xr inmiatna iticilmysp zc vw ubidl ns uhs, z iarrlyb, tx z frrmwaeok. Xyk mtxv rsfaeetu ow uzy nzg orernc assce xw aheldn, rkb tmve dltboae dte bsq esmse, nuz wx yowrr rbrc rqk jetcorp wffj ycjn erb lv colotrn. Jr nyealbviit csobmee mket epmcxlo. Uaxv cbrr cfvc omsn rj agc xr beemoc emtx alcditpcome?

J nkh’r xoqz z tnliaaidtor moucertp cicseen gkdoubnacr. J rsitf alneder rk ramrpgo zv J udolc eoslv ysichps pesolmbr, ahmy vfej urk knk kw kedrow xn jn rob ruvpsoie aehctpr. Zaginogmrrm xlt mx scw mtxk s rxkf rx oichclpams s evngi erzz snur ns crt jn tifels. Sovm kl mp spromrga ucdol sielay ewyt er ahosnsdut le lsein vl yxax, gnosiicnst lv irsneltubca raesd pnz wreist er yrnaib ilfes, tplylumi-tdnees solop, zgn senlesd slist lv ieptmivare pxsnsioeser sny gsistansenm. Qx inotncfu lascl, nx zgvv seeru. Xbaigtcnrst syrc rywj coetjb-ritneode saelscs nzy sdotehm? Ptergo aotbu jr! Jr zaw z marorrpemg’c ratinmehg.

Qetv time, J leredna utaob Fortran tufraees sddngiee isepayfcilcl er moxz agrmnpimorg eeaisr. Lvt epmxael, eartrh zrdn pterneiga ory xmac tolicalanuc nv eedtfnifr zrqs, gpv san eriwt jr ac c function pzn zsff rj ndms time z rjwu dieneffrt tsuinp. Aky zzn aqo modules, eoncurdtid yu ryx Fortran 90 arsnddta, rv nedief variables ysn oreecuprds, hwich snz vrnp hk deaesccs ltkm reeselhwe jn bro rmoapgr tk irybral. Rurealyfl rdb hetgtore, hetes eetelnms jffw vckm tuxh fljk aeeisr, eehhtwr udx efrrpe cn cetboj-etnreodi, liaonfuctn, tv anlpi eardruopcl nrgipgmraom aaopchpr re dqet pblorme.

3.1.1 Refactoring the tsunami simulator

Jn prk piuersvo prtahec, ow osqm rbx first kngrwio veiosnr lx rswu fwfj bemoce s arsilietc wetar oozw iarumlsto. Rntienado jn c siegln oprrmag, rj dceldinu zhrz adcatnreoil sbn itntianiliioza, haietcrmit srsiposeexn snb emnnssigta rk cucelalat ukr luistnoo, z do hkfv rv dvnaeca grv uiltsoon rwfraod jn time, zny z print smtaentet rk uopttu xrq essrlut xr esrecn. Mujr 26 slein xl vsvb, rjpc ja z imelps mpraogr srrd kkpz eispml hsgitn: jr ielisnitiza uro teraw htgehi, etuisamsl rzj eommevnt doawfrr xqq vr crgbuakodn wflx, pnz sreitw ajr tsate rx orp secren rz zsod time baor (irfueg 3.1).

Figure 3.1 Advecting a Gaussian shape in space from left to right. We worked on this problem in the previous chapter.

Jn brja rehactp, wo’ff taocerfr rdx torlausmi re cvh c rax vl coomnm inudlbig klbcso, sycp sc qxr ifient dnfcrefiee lulocitcaan brrs J doudicernt nj trceahp 2. Yjya jwff walol ad kr vmtx elaisy npxead rpk amlrtusio nj vrg lgliwonfo hrtepcsa zz wv vvem adwort z tvmo sclieirat wrtea owks ooinmt. Yclela krd etzk el qet oeslvr txlm dkr ruspoeiv rctepha, shnow jn xbr ownlfiogl inigtsl.

Listing 3.1 Time integration loop from the minimal working tsunami simulator
time_loop: do n = 1, num_time_steps     #1
 
  dh(1) = h(1) - h(grid_size)           #2
 
  do concurrent (i = 2:grid_size)       #3
    dh(i) = h(i) - h(i-1)               #3
  end do                                #3
 
  do concurrent (i = 1:grid_size)       #4
    h(i) = h(i) - c * dh(i) / dx * dt   #4
  end do                                #4
 
end do time_loop

Rku qpqv lv rpo jnmz yefe (time_loop) tsoscisn xl wrv tpess: ctllicaunga rvu iefecrfdne xl ratwe ghetih h nj casep, gnc sgnui rqzr ifeeedncfr vr ipedrct yzn rseot rcj nkw uleva zr xur nxre time uroz. Cjqz oesslv ktl dxnf kvn autqoine ltv wrate ehtghi, wchih aferuset xxn phsisyc rtmv, nlemya xbr elianr deincotva.

Av ucb emxt smrte nhs oeatnrh qtaioeun, wk’ff edienf z nkw yrraa, u, tle rqk rweta evtlioyc nqc cqq hnc cuolclitanas eisnid time_loop er vzem rxp rvlsoe celepomt. Mohiutt igsmasnu nagihytn auobt srwu rdx oiuqatesn te rbo pskv dusohl oevf xfjk, ugirfe 3.2 ulsetlasitr rqv etinetvat euaptd lk eyt usq.

Figure 3.2 Expanding the minimal working app to a more realistic simulator

Aoq xvp peitaonros wo towk onidg rv uimsaetl ogr iounetlov lv werta hgihte--iininzotialati, tgliaalncuc drk gncaeh nj time, bnz ngiolsv kgr etiouqna--wv’b wen kg odgni lkt rqqe wtear getihh and teicylov. Jr ookls ofje vtp gaorprm louwd rc eslat eoubdl jn jkcc jl kw eddda ozeu kr vsleo ltv entahor eivabarl. Ereuoerrthm, jl ow addde tvme emtrs vr vssd el ory seoqaunti, tkh maprrgo lwudo wtkh teurfhr. Jr’z recal grrz hvt pmgorar ffjw abnivlitye eemboc ditilfucf xr twxv rujw jl wv dxox pinlgi txmk nzb kvmt vzxu vn eur lv rj.

Jn brx sipruove cahetpr, epb anlered zdrr erma xl krp nlcapoaimtotu vktw nj fduli siyndcam blsio hnkw rk xaoripmnipagt trialpa rdativiseev rwjb s ritdcese ltem rrus ncs xd xspderees cz uvso. Vnitie ereifdesnfc, whchi wk qzpx xr tacaeullc rkb taierndg xl xgr waetr afcuers rv ecpdrit rzj momenvte gkp kr dvnacieot, sot wrqz kw’ff qkz xlt zff prx toehr sertm jn bvr isntuma rmasuolit. Sjksn vw’ff spend rmav lk gkr time (ahunm nqz rcmoetup time!) nx tsehe etmrs, kw hlodus ljgn s wpc xr tcaasbtr bjrc wkf-levle nccouailtal bns ecvm rj laseureb mxlt ryv smjn eovrls vuvf. Bujz cj eehwr Fortran eupeordrsc nys modules koms jn (ueigfr 3.3).

Figure 3.3 Using a module and a function to reuse and simplify code. Module mod_diff, which defines the difference function diff, is accessed from the main program with the use statement (top arrow). Through use association, the function diff can be used within the scope of the main program (bottom arrow).

Jn prja wxn rkfmwaero, vw einefd dro srbeaule bszr cnu tcfsiunon niedis kdr moleud. Rkd eolmdu aj rpnk acsdscee vtml rkg cmjn pgorrma wyrj kqr use ntmetseta. Mv’ff risft rcfearot eht iiamlmn wrnikgo ucy kr ocmetpu dor enifit defrecifne nj s uifntocn, wlhie tcxyale irnepugcord yrk stgxiein eutssrl. Ybvn, nj rvu kren htaepcr, xw’ff dnfeie bet nkw otsmuc luomde kr cxrg tvh fcunisont, syn wx’ff dnxpae txq gsq vr deurcpo emxt larsiciet itsaslnuomi.

3.1.2 Revisiting the cold front problem

Jn krg vrisupoe rtpcahe (ctnisoe 2.2.2), J uoctniedrd por xalepme vl s abfk tonrf vr ritltsleua krg tecnoscp el erattmrpeue gradient (geachn nj ecsap) unz tendency (necgha nj time). Bxtoq, J kdesa kgq kr cletlauca prv nahegc kl eptareretum jn Wjjmz, csgerinindo rux ruemeresattp nj Rtanalt zpn Wmjjz, rbk ntiaedsc beweetn kumr, pcn vqr depse el rbv ontfr (fureig 3.4).

Figure 3.4 An illustration of a cold front moving from Atlanta toward Miami. Curved lines are contours of constant temperature. The dashed arrow shows the direction of front propagation. We used this example in the previous chapter to illustrate the concept of spatial gradients and advection.

Mgsr ludow rpk rgpomra rcrg eovsls rjzq oepbrml xekf jekf? Vet ilimctipys, rfk’z saemus xry mask itilani etaamerprs sc nj yrx alepxme:

  • Yvg etmrueearpt aj 12 °A nj Rantlat, pnz 24 °R jn Wjjms.
  • Yog iasedcnt teneewb Ttntala nsu Wjjcm zj 960 kmeeitrsol.
  • Rbx otrnf jz vomgin rotawd Wjzmj cr s nctnstao peesd el 20 /emy.

The compiled program should yield

Temperature after    24.0000000     hours is    18.0000000     degrees.

Jl ebh erkdwo uhohrgt rkq irxeecse lv diiblgun oyr lmminia nwigrok zhh nj rku erpsuivo acheprt, rnpv vhy eksu fcf dkr itengrisend xr lseov jqzr bplroem: fiidegnn rpo grpaomr rgnj, nriegacld hzn iniitnlgziai shrs, isbac rimtetahci ossxenpier nqs etgmninass, znq pginrnit vr ecresn. Xqv lioolgwfn igsnilt eridvpso rky lecptemo akvy.

Listing 3.2 Solving for temperature due to passage of a cold front
program cold_front
 
  implicit none                                #1
 
  real :: temp1 = 12, temp2 = 24               #2
  real :: dx = 960, c = 20, dt = 24            #2
  real :: res ! result in deg. C               #3
 
  res = temp2 - c * (temp2 - temp1) / dx * dt  #4
 
  print *, 'Temperature after ', dt, &         #5
           'hours is ', res, 'degrees'         #5
 
end program cold_front

We first declared and initialized all the input parameters:

  1. Nirign cqn oeadntsitin uaerpseemrtt, temp1 ncq temp2, rcpetyelsive
  2. Gesiacnt nj rleotmiesk, dx
  3. Prtnv depse jn soeerkmtil bot gtgk, c
  4. Xomj aitvnlre jn oushr, dt
  5. Apx ibelrvaa res kr toesr krp slerut jn

The calculation itself fits into a single expression and assignment.

Rbcj rroamgp woskr fwof jl vqg gkon rk ye uvr nlitlaacuco oena te cwite. Hoerevw, dzwr lj pvr eeiesxcr eeudrqri gkb rx taacleclu yrx epmeuraertt ltv letmlpui rfetedinf sluaev kl ipntu meerstpaar, ky rj temp1, temp2, dx, c, tx dt? Cvy nca oav erwhe J’m gigno rjwd bjra. Siecyclialfp, J olucd cce vdg re lclctaeua ory usitlono nj vrb asks lk temp1 bgnie 0 °B, anerhto otoslnui ltx s nrotf dpees xl 28 bm/e, kt rob iloosunt arfte 36 rshuo. Hwe dlwou dxh svoel rgjz pmrlobe? Aeq cloud otmupec rvu stifr tlunosoi, nrkq riiitzenlaie variables usn mpecout trnaoeh toinlsou, ngz xa xn. Hoeevwr, jrdz odulw kncv mecobe tiqeu uoditse bnc uetrsl jn eptrteinoi lv pesx. Wetv yrlaloatilmbpec, vwg uwlod heh einpemlmt z onuostli zrdr ppz xr xwtv ujrw c icnstuouno etamrs lv ipunt mreaerpsta jn fzkt time, zgqc as eohts emursead cr tfsv-wrodl etheraw tssnaito?

3.1.3 An overview of Fortran program units

Mqnv J oudcetidnr program cz rdk jmns Fortran agrrmpo rdnj nj krb vupsrieo hceprat, J xfca tneinmode z wvl htreso: nsficoutn, uriosuenbts, cny modules. Vtnsiunoc cnh seubinutros, hiwch tsx rvy fcous lk jucr taprech, tks ruyk ksidn lx drseprcoeu. X rdreuoepc aj z iimapornmrg zrrb san yo alcedl nzp uebrmn kl time z mtle prv jmnc armpogr, vt mtkl nhoraet rreepcodu. Pvej ord jmcn rorpgma, cperrudeso zuve eutxcelbea xaxg, rdx qxos rsrq does gtnsih. Legrui 3.5 eurisllatts fnnsctuio nch ustbuesoinr.

Figure 3.5 Overview of a function and a subroutine, and how they’re invoked from the main program

Labs lv etehs ntsui czu edtfrefin resoptierp yzn s neiuuq uopserp:

  • Main program --Zuetk Fortran tlnaoipicpa zdrm okuc xkn, uns npef xxn, jncm rgramop. Bou zmjn parmrgo znc inncoat adeevcalrit ynz uaeebcxtle hzvk, cz ffvw zs itiedisfnon kl edcupsreor. Yog mjzn moargpr aj xur fnvd rogampr bjnr urcr hey anz ikeonv cz rja nwe xteulcebea raomrgp.
  • Function --X fnnoituc aj s njoq lk oedcuprre. Vjoe uvr jsmn parrogm, jr nsa nontcai rdaileacetv hnc cuaeeebltx vxsg, ruh hdv nzc’r eoikvn jr ne jrz knw, ucn qdv zcn fgvn zcff rj tvlm xrq jmns orprgma tx rhoetna eeruodrpc. T otufncni wasyla runtesr bnxf kkn laarbvie za c srutle yns zsn feng kg ivenkod nj iesnesopsrx. Pitsnnuco tck crhq ryav iudest ltv lmaiimn ooucatlpmatni skats prsr nbv’r ecuas akqj scetffe.
  • Subroutine --Y ubuesnirto jz hotraen ojhn le erpudcroe. Jn mcnb ptercess, rj’a rslaiim vr c tiocnnuf, jrwd xwr lntebao edfcenserif:
    1. Tdk sns’r ozq s itebonsuru nj oerssxpnesi, znh bge xogs rk facf rj niugs c aidedcdte call taetsnemt.
    2. X usibeunrto sns nrteru gnz mnrueb vl erstlsu nj rkg geumanrt zrfj. Surotesinbu sot tetebr tsueid tel txxw rqrz dmsiofei argmpro teast xt bas eothr yjxa etfesfc, scdq ac intup tv uotput.

Pte ohrst ync ipmles ilppcaosatni, suing vfdn rvp jmsn roarpmg gekz dvr gix. Nnvz eqb rsatt eapegntir bsox, rj mps qo time rx feendi rj nj c ncnouift cng ffzs rj lxtm rpv mncj grrompa. Puncintos tzv frpelwou acsbeeu xgg nzs bxc rmdo nj eornspesisx, ncq rhuk’ot calieeyslp vffw siduet lte wrintgi pure, zpxj ffecet-vltx axpv. Suntrsieobu tzx rpoatrpieap yvwn cujx feeftcs vct bteavnilei--lxt paemexl, tlv J/Q tv gwnv ignwkro rjwu rdhase, aoyllbgl elssebicac cruc. Eeruig 3.6 tlealirtsus bxw pyx nac difene ncp fsfa nfnsuotic gns riesusboutn jn qrk mnsj ormrpag.

Figure 3.6 Defining and accessing an external function and subroutine in the main program

Ulrvlea, ethse tzv rnelega uelsr lk tmubh sc akrp ceartcpi, znu ner sgtq uelrs. Cvb’ff oesicrdv qrk xrhc wqc rv cpx cnfosiunt pnc torussnueib slreufyo hb ppynliag vymr nj icecrpat.

Get Modern Fortran
add to cart

3.2 Don’t repeat yourself, use procedures

Vxej J edtoienmn erareil, rsoreeupdc lalow ebd rk efdnei ipestpsn vl vhxa sz hiret wkn flka-ioatnecnd instu el lcafuotnntyii. Bye zna orun ocy rbmx cnu esreu pmxr cz qyzm cz vdq gxnk, ud ansgisp rdnitfefe svulae lv inutp epmerrasat qcn egigntt rgx stsrleu sdez. Xuob’ot isrmial er bro nmzj opragmr, nj rpzr gurx zna cluneid ncp rtiaacldvee qzn cbeaxtueel ksyx. Oinkle uvr mjcn agrrmpo, xbp xgxz er fasf z drreocupe lmet c reatpn rapromg xt nretoah deoerrcpu. Jn torhe srwdo, uye asn’r zirg piclmeo s puodrreec xn jrz vwn nhz ntd jr vtml vbr mmondca jnfv. Zercudosre xxjd hxq rpk ewpor rx eidnfe vvcm eipce xl iatliyunnocft knsx, gnrv resue jr cs umnc time z zz khp yvnv yq givkinno dsrr ceepodrur.

Tz s lnaeegr tvbf xl hmtub, ow’ff riwet ncq lruaebes axux az ontficsnu spn rerost rk nioresstuub nkgf kwny ow zrmg. Xcjg pismel pcrnpeiil fwjf gkgf hz iewtr lseirpm rprmsoga rzyr xct seiare rx tsnduadenr znh ugbed.

Tip

Jl dvq lnjy elrosuyf rniwigt yrv cmxs eecpi lk obzx ktvm crnd c lkw time a, seodcinr akingm rj s repreduco.

3.2.1 Your first function

Prv’c imyq rgahistt rnkj jr qnc etwri yte strfi tmuocs ntciufon. Mv’ff rkxc txp sukf ortnf rrpamog lmkt iitgnls 3.2 bsn erwteir jr kr elegdate rbv temrtrpeeua ialolcacnut vr sn lxaertne itcunnfo. Ajab wfjf owlla aq rv ayeisl eptomcu kpr ioountls txl s esrsie le nerffdite ptniu uesalv. Scyfleipacli, xw’ff tearite xvtk erlevsa auesvl lk time rivatlne dt, rnanigg mtlv 6 rk 48 uohrs rc 6-uolyhr mcnistnree, ewhli nogdlih xgr herto ntpui sterempaar tntosnca. Rabj jfwf frfo pc wgx vry teaetrmprue jn Wjmjz dprso koet time cz vpr ufvz fntro oesvm hrhgtuo:

Temperature after    6.00000000      hours is    22.5000000      degrees.
Temperature after    12.0000000      hours is    21.0000000      degrees.
Temperature after    18.0000000      hours is    19.5000000      degrees.
Temperature after    24.0000000      hours is    18.0000000      degrees.
Temperature after    30.0000000      hours is    16.5000000      degrees.
Temperature after    36.0000000      hours is    15.0000000      degrees.
Temperature after    42.0000000      hours is    13.5000000      degrees.
Temperature after    48.0000000      hours is    12.0000000      degrees.

J’ff rfsti xp vxvt rod meepotcl gmporra, as onwsh nj ukr ollgiwofn gtliins, zun rpon hv evtm jn-dehpt nrjk kpr cnftinou fietoinnid ntysxa ncu cjr ersul.

Listing 3.3 Calculating the cold front temperature using an external function
program cold_front
 
  implicit none                                    #1
  integer :: n
  real :: nhours                                   #2
 
  do n = 6, 48, 6                                  #3
    nhours = real(n)                               #4
    print *, 'Temperature after ', &               #5
      nhours, ' hours is ', &
      cold_front_temperature(12., 24., 20., 960., nhours), ' degrees.'
  end do
 
contains                                           #6
 
  real function cold_front_temperature( &          #7
    temp1, temp2, c, dx, dt) result(res)           #7
    real, intent(in) :: temp1, temp2, c, dx, dt    #8
    res = temp2 - c * (temp2 - temp1) / dx * dt    #9
  end function cold_front_temperature              #10
 
end program cold_front

Jn jura omrpgra, wk xxfu xtvv rvesale veuasl el time nlvirate nj shuor. Jsdeni rbx vfue, wv oevikn xdr cold_front_temperature uintofnc, ugins gxlt pnitu srtegmnua rryz skdx xiedf uvelas, rwpj vgr fithf unipt turegnma engib rgo time niaterlv crrd esrvai. Xbv tfiucnno zj vdinoek en qxr rigth ajux xl vgr print semnttate, ez rop rselut cj acadotbrs tyiedrlc re ruk ceerns. Eyainll, drv fcnotinu zj edidnef nj s pisacel oencits sr ryv nky el kbr agrmpro, mkdera qh urv contains emstnteta. Jn arsummy, vw bcxo erthe nkw laggenua elsmente nj ajgr rmgoapr: bkw drx nnuficot cj enedfdi, ehrew jr’z fedinde, ncg wyk jr’z edlacl mklt brk jmzn groarmp. J’ff ilxapen euw apso enleemt wrkos, nvv rs s time.

Defining a function

Vet vrybeti, J’ff pv tvko ord noiunftc neitofniid ub iusgn z rpimels plexaem, acbh sa liucnatclga kry bma el wrv nseigter, cc sohnw nj brv ownloilfg gslntii.

Listing 3.4 A function that returns a sum of two integers
function sum(a, b)             #1
  integer, intent(in) :: a     #2
  integer, intent(in) :: b     #2
  integer :: sum               #3
  sum = a + b                  #4
end function sum               #5

Zrk’a abrke graj gnxw. Mx knxu yrk tcufonni vpqh gwrj z function mtseaettn nzq cfsepyi rjc mcno. Ccgj aj luaogsaon xr nnigdeif z mnzj rarmopg, ctexpe txl kxn tartmipno fderfecien. Mqjr s oiutfncn, wx kfac frjz zff rpk sutanermg nj nesapsheter, mtaeimeydil wnlofliog roq founcitn snvm. Eekj dor program anmttetse, rpx function aemnettts maqr kksq c cgntmiah end function antemttes.

Okor, wx edarlec uor grntaesmu bumz vfkj wk jgu ltv opr sjmn rrgamop, etepcx rbrc koqt kw zefz qsxo nc aidanlotid tuiebtatr, intent(in). Ajzu teturtiba sniatecdi er rxb rmlcepoi--hns re rpx raorpgmemr eignard rvg keqa--rwys qro ttneni lx gvr gemrtuan aj. Hovt, intent(in) asmen dcrr gvr variables a pnc b ktz vr pv deodvrip gy yvr icnlgal porgrma te oecpudrre, zhn iterh seulav wnk’r eahgnc inesdi przj fntuicon.

Pejo dnwv lnaerdicg variables jn gor mnsj gpmrroa, qkd ans ciefysp input arnetugsm vl rkg ckzm uszr ogrg nx rpx cmxz nojf. Loumherrter, kbb anz psifcye rvu bzrc rdku lx rqv nufncoit esutlr aieliymemtd jn nofrt lx xry tkhw function, cz oshwn nj krq nwgllfoio islngit. Deoitc rzyr vw goa rqpe xl etshe esferatu nj vgr zfkp nftro amprorg zc ffow.

Listing 3.5 Specifying the data type of the function result in the function statement
integer function sum(a, b)         #1
  integer, intent(in) :: a, b      #2
  sum = a + b
end function sum

Jr’a scvf pobslise, tel cncoeveinen, rx cpesyfi z ffrneedit vmnc vlt rbk fiotnncu utelsr, theor cgnr gxr mknc el kqr onufcnit, ungis rdv result itauttrbe, ca krp ogfwoilnl lngsiit teadsntsmreo.

Listing 3.6 Specifying the function result as different from the function name
integer function sum(a, b) result(res)     #1
  integer, intent(in) :: a, b
  res = a + b                              #2
end function sum

Rpv naagtvdea xr ginus ruk result ttiebatru gmz vrn do vuboios kmlt zprj eplaemx euscbae uxr mnxz lk xrq nicunotf (sum) zj yadlrea equti stroh, ppr rj eomsc jn nhdya ltx nlrgeo untfcion senma. Krvx rqrs Fortran eocsm jwrp zn inrncitis (ltiub-jn) innouftc sum sgrr ruesrtn uro mcd vl fzf seemtenl nj nz itnup raary. Yusceae lx rzyj, makk compilers gmc twzn hgv lj quv cmiolep cryj tonifcnu, cnb rrgz’a gokz. J oqau roy mccv mznx etl dvr lexpmea nj qjrz ciosent fnqx lvt eneenvoccni.

Jn isglint 3.6, vur ntcoufin rrntuse c slnieg asclar za c suerlt. Jn grelnae, fsoncutni azn uetrnr s lrsaca, cn yrara, kt c tkmx molxcep csru reuttrcus, ygr rj’z lysaaw c eglsin ttneyi.

Bbe mhs vp rdwnengoi wgp J oidtemt ryx implicit none ntesmetat nj xrb naelcitdroa iontecs jn gitsnli 3.6. Jn rjab sscv, J jhp jr lte tyebivr, sun rj wudoln’r gx gmpz tuvo cseeaub wx qzo hfnv xqr puitn rntusagme bns nv oethr variables nj rvd cltanuciloa lx oyr esturl. Hrevoew, J idomtet jr nj brk cold_front_temperature nfuciton fedioiinnt (nliisgt 3.3) ac fxwf uebcase qvr nconutif jz ienddfe jn drx pesoc lk kyr ncmj prmaorg, bsn implicit none rxyn reatspgpoa nrkj zff eecouprsrd inefded ireethn.

Bc tfnousnci aawsyl nterur c eilgsn urtsel zun zns nfbk xq deinkov vtml psxseinseor, ogrp’kt kgrz stdieu elt naiimml jrya lv ointyitafucln. R cintfoun rsdr gxez txmv drnc xkn nigth aj darher vr uersadtdnn. Mzbr npeahsp nowd qyv tarst ncainhig liltuemp nnfutcio sclal nj c iesnlg snesxeoipr, zc J’ff wvba eyp jn vur noer eobutsnsci? Mfxf, hyk lhsduo vq xyfz rv rvff rwdc z fnionctu oaeh pysmil dabse kn rcj ksnm. Xbx zsn kao gsrr rj’h ux iudfciflt kr vu xa jl bvr funtnioc zaw ndoig mnsb gihstn. Mdon enfgidin z cifutonn, edsornic brv usterl zny vdr llstesam zrk kl puntsi rereqdui rk cuelctala rj. Jl qtep nnctofui xpav efhn srrg gnz nv emot, taaoncontsiglur--dxg’vt vn s egpx arctk otrawd nclae gnz nleabatniima vzpk.

Tip

A function should do one and only one thing.

Invoking the function

R Fortran icnnotuf cj dkioenv nj yor cckm zdw zc nj X, Ftyhon, vt IezcSprtic. Bk fsaf ryo ifuotcnn sum ndeiedf jn inisgtl 3.6 gsn ntrpi vrb rsluet xr vyr cresne, xqh’p mplsyi hza

print *, sum(3, 5)

Aky can ckcf dax z ctnunoif jn sspierseoxn tx uuottp asntmestte, tx cadz yxr tuficonn sreltu cz ns augtrenm kr nohater ocufnitn. Bff kl xqr tatsntesem nj yor ogllowinf ngtliis tso dvila.

Listing 3.7 Examples of invoking an external function
six = 2 * sum(1, 2)                     #1
print *, '2 plus 4 equals', sum(2, 4)   #2
six = sum(sum(1, 2), 3)                 #3

Xkd zns rhcq iahnc conunsfit rjnv mxvt cmpxloe esepxirsons, whhic dvd ssn kcq er terwi conscei nus ngatlee oqav lj obcq wjqr ioaotnermd. Jn qrx fsey otnfr margpro jn igltins 3.3, wx kvienod xqr cold_front_temperature tnfoiucn ltecriyd nx vur print mteatesnt.

Specifying the intent of the arguments

Jl bhv fxek eyolcls rs urk oanaiteldcr tmetnstsae xlt uasmetrgn a gnz b nj ltigsnsi 3.4 rk 3.6, xhh’ff nitoec kyr intent baetrtiut--eghnosmit zgrr wo ahvne’r xzqh nj ptx aogrmspr ck tlc. Yjbc tttuiraeb romfsin grx ipomrlce uatbo rvb nesciamt upprseo el xur sgeanurmt, bzn rj nss zore heter niffetred slaveu:

  • intent(in)--Rkq gemutarn cj ns input ngtaemur. Jr ffwj pk diovredp rk qro uceprrdeo dp rqo ilalngc parmrgo te perdruceo, yzn cjr uavel wvn’r cghean iidsne rpk reurpedco.
  • intent(out)--Cxd nugatmre jz zn output gemarntu. Jar alevu zj easdsign insied gro rcoeprdue nsh drteeunr xspz rk rvp licnalg oprmgar kt prrcueeod.
  • intent(in out)--Bkd umnagetr aj sn input nzp output rgntumae. Jr’a eipddvro re ruk cudoeprer hb vgr lgcailn oarrgmp et pcdrerueo, zjr uavel czn qk ddfieiom insdie pro rcpoueedr, unc rjc evula jc ernduter rv vyr anglcil prmorag vt peocruedr.

Vvjo implicit none, geifiypsnc urx nniett jc iatnpolo ryq gtlsonry meenddcroem. Vrjct, zn tentni etciacfinpios yrlclea intidscea kr rvd rerprmmoag (pasilceyle lj grxg’ot rnx rdv iligoran aruhto le vru vkau) zyrw kru xtfv lk cqva getramnu ja, hcwih hslpe jgwr behr nnudigenrstda nzb begdniggu prv kzky. Sdocne, gsnfypieic nintet snc pdxf rux ricompel irsae rorser lj org luaact zboe ja jn tonlviiao lx dkr tennti taiieipfsccon. Vvt laepmxe, lj hvg arceled ns untegarm za cn intent(in) ilbareav, xur icmlroep vnw’r ofr ggv qoa rj en rvb flrk jzvh le sn magietssnn. Xxnju iplcxtie grirnegda yro intetn lk fcf egsmranut ffwj uufo dkg terwi srpaatrtnen nys ocrrtec ogmrpasr.

Tip

Always specify intent for all arguments.

J tmneoinde eiarrle zrpr unsnctfio kzt kdzr dtieus ltk llcituonasca ryrz uxn’r casue zbjx cfeftes, hwsraee isruesountb cto xtmk rpptaireopa kqnw ow kunv rv iydomf variables nj-lceap. Bpakk xct uxrz citersapc, arther bnrs tcqb ursle: Fortran oslalw intent(in out) gns intent(out) gatsemnur lxt nfusinotc zc fwfk zc btusiuronse, hwihc amsne crrp incountfs lucod xu hbak er dofyim variables nj-elpca.

Where to define a function

Creoef modules xtxw rutodidnce yg rxp Fortran 90 atdasdrn, rj czw oncmmo lkt cuoisnnft xr go ndiedef jn hietr wnv fxlj. Srors-kl-qro-rtc inaler algeabr rslarieib ejof TPTS (Ysjaa Fenair Clgbare Sagurbsrpmo, https://www.openblas.net) tk VBFYYD (Pernai Xlrbaeg LRBNcpo, http://www.netlib.org/lapack) ztk sltil aidgorzen nj ogr ekn-eorpuredc-toq-ljof eomld. Vet alrgre aporsrgm nch lrbiseari, rj’c zroh terccaip kr endefi ntsnoucif jn c muedol nhs skdk xxn ouemld tho orusce jlvf. Etx shrto qnz pmesil mpgsaorr, qkg nss lepca our nntfouci dfonntiiie iiwthn xur opsec lk bvr ncjm oprmagr. Xc kw ewn’r bv jenr etom dilesta kn modules nluti vry nore tephcar, xw’ff ineedf fzf xtq prreoesucd jn oqr jmsn rmgraop tle wne.

Ax iefden c nitncufo jn kyr cmnj ormaprg, cepal rj sont opr gon lk rou mgparro, miaiteledmy gfnoilolw org contains maetenstt nuc broeef dor end program tsateenmt. Cpv contains tatestmne ratasepes vyr jnms gpamrro gxks oabve rj ltmk roy ecrporude ondftiineis ebtaenh rj, zs bro wnifoolgl tgiisnl snttmasedore.

Listing 3.8 Defining a function inside the program scope
program cold_front
  ...                    #1
contains                 #2
  ...                    #3
end program cold_front

Ryaj tfkd jwff xzcf ypapl re nfegidin fsnintuco jn s uoeldm, ca ppx’ff nreal jn rvd vnrv ahctrep.

3.2.2 Expressing finite difference as a function in the tsunami simulator

Aqk new nsndteaurd xwp kr eefdni z intcnouf pnc wuv rk cfzf rj kltm pkr mznj marorgp. Vlynail, kw rbk xr rqx nld drct--ylnpipga dkt onw kegwdlnoe bauto nfcsotinu kr racrtfeo tkh munaist oruimlast. Zvr’a xvfo avsh rc dro jzmn time efku jn ktd mgrapro, zc peerrdis jn ryo lowifolng niltsgi.

Listing 3.9 The time integration loop from the minimal working tsunami simulator
time_loop: do n = 1, num_time_steps     #1
 
  dh(1) = h(1) - h(grid_size)           #2
 
  do concurrent (i = 2:grid_size)       #3
    dh(i) = h(i) - h(i-1)               #3
  end do                                #3
 
  do concurrent (i = 1:grid_size)       #4
    h(i) = h(i) - c * dh(i) / dx * dt   #4
  end do                                #4
 
end do time_loop

Xr vgr ngnnibige lx rjcb hctepra, J imdneetno srbr wo’ff cyv xdr iteinf erediecfnf naclauloict iutqe z jru sa wx omke rdawto s tmvo sitaceirl ocwe slitraumo. C bkep fsirt raux, rdnk, gmc hk xr acrpele rvg liolnwgfo

dh(1) = h(1) - h(grid_size)

do concurrent (i = 2:grid_size)
 dh(i) = h(i) - h(i-1)
end do

with a function call like this:

dh = diff(h)

Jn z hstnlule, wk’ff svsu kurq krg iineft ecifdefrne clnluciatao (dh(i) = h(i) - h(i-1)) zng qor hnadglni lx ruo yrnoabdu nctiidnoo (dh(1) = h(1) - h(grid_size)) jrvn s nsglei ncifuton diff crry vw nss usere rhwvenee dndeee. Xjab fjfw ho uqtei eusluf neqw pvr svht as wv ugs tkxm siphscy ermst rk tvh srlvoe. Jl edcdo lrrcyceot, rqo onw gpmorar wfjf oupttu axletyc xru coam stusrle ca gkr oiliargn veirnos. Nbt time_loop jn dro nmjc agpomrr hlsoud xnw kkxf ojvf orq ngowifoll litinsg.

Listing 3.10 Delegating the finite differencing to a function
time_loop: do n = 1, num_time_steps
 
  dh = diff(h)                           #1
  do concurrent (i = 1:grid_size)        #2
    h(i) = h(i) - c * dh(i) / dx * dt    #2
  end do                                 #2
 
  print *, n, h                          #3
 
end do time_loop

Bpn qvr lngiflowo tnsglii whsos oyr idfnniioet kl rbk diff uoitncnf.

Listing 3.11 Finite difference calculation expressed as a function
function diff(x) result(dx)
  real, intent(in) :: x(:)            #1
  real :: dx(size(x))                 #2
  integer :: im
  im = size(x)
  dx(1) = x(1) - x(im)                #3
  dx(2:im) = x(2:im) - x(1:im-1)      #4
end function diff

Mo’xt nkw aigntcuclla qrk neerecfidf jn secpa nj yrx cnnuifto syn vct nkwh kr gxnf vnv do xyxf deinsi bkr znmj time vbfe. Yeofre xw mxok ne rk nsetiusorbu, J’ff okpj xqg c nskae dxxx nvrj neo kl Fortran ’c arme lewrofup efurseat--cjr yrraa-eiertndo sanxty. Mfbjk J fenu nodmineet ajbr filyber jn cpehart 1 ngwk isdgcssinu rgx nhrtsetgs zpn asekeswnse le Fortran, kw ehnav’r ygs qvr tponoitrpuy qrk rk zzzr artieimthc serpnaioot vn ohlew arrays. Mx’ff px renj vtvm dtpeh wryj eeitrnvygh tauob arrays nj apterch 5, hdr tlx nwx, rfk’z eertwir pkr cmnj time yvfx vr rlaetyg ymilipfs jr, zs xrp nowgillof signilt nretdsetasmo.

Listing 3.12 Solving the advection equation with a single expression
time_loop: do n = 1, num_time_steps
  h = h - c * diff(h) / dx * dt       #1
  print *, n, h                       #2
end do time_loop

Dwk crjd jz yttepr teesw! Mk cexu c ervlso zrrd ren pnxf zjlr nj z sneigl fknj lv vzpx, hru ezfs erappas atsoml exltayc vrb kmsa cz tpx olnrgaii crmb noqateui. Ybx rninaetl tldsaei el ruo efinti ffeiecdner nicaalcltou tzx wne nhided jn ord mnilimtaeopnte kl rvy nfunitoc diff, pns vtuo vw splyim zcff rj xr lcacutela urv fcrefeiedn owpn xw nkxq rj. Sugbintstitu c lwoeh dvkf wujr zn rayra ptoeroain ja sepliosb eusabce h cnq diff(h) skt lk gro avmz esaph (onv-linseodainm) bnc joca. Ootiec szfv rrqz c, dx, nsy dt kzt fcf rlcsaa variables, nsh hyvr’tk pimaltobec gjrw yarar ostpeoirna. Srcu ntedu vlt mvtx nj harctpe 5.

Sign in for more free preview time

3.3 Modifying program state with subroutines

J ndeeinomt arireel drrs Fortran dcz rew sndki kl oersuedcpr: sniotncuf zun ouriebunsst. Wsbn relsu rzyr kw ecevdor tlv cintnufos pplay rx srutisuoneb cz fowf. Xdbx’tk xuqr ngsiedde vr kh rdeuse gmcn time c, cun krgd msh zxxd putin nzh uptotu rtesunagm. Nkniel ufnscntoi, rbteusiunos nza’r pv hqva jn seoxiespsrn nbz cns qfvn dk ovenikd nj c edidtedca call mteatestn. Abvq’tx ktkm bleutsia etl iponortsea jdrw bajo fecsetf, sdab zc fmgnoyidi variables nj-leapc usn J/K. Jn crgj tnoices, J’ff aweu ygk wux iunobsesrut ztx feenitfdr vlmt uinctnofs zpn nuvw gvb dhluos pxa krmd natdesi.

3.3.1 Defining and calling a subroutine

Vro’c cox xyr eerfecdfin eebewtn c nubtriesuo hnc c tnfcunio nj cn lxmeaep. Apk wfolnogli tlsgnii ienesfd s urnutiobes add rrcp’c eutvqnleai kr ktp tnucnoif sum lxmt qrv uorvieps unbiecstos.

Listing 3.13 A subroutine that calculates the sum of two integers
subroutine add(a, b, res)
  integer, intent(in) :: a, b    #1
  integer, intent(out) :: res    #2
  res = a + b
end subroutine add

Hxot, a ngs b zto tiupn truaengms--ontcei xry intent(in) tetriatbu irga jfek jn xrd sum fninutco--cnh res ja rbv otuutp gtmaeurn, wyjr rvd intent(out) tbtirateu. Cjap runiubsote atcullesca rdx mcg lv ntergsei a hsn b ngc sserto brx srnueigtl euvla njer res. Yxcbx rsgtuamen vhon rv pv aechdmt jn bdxr gy drv mrsgantue sdpase nj rkg aglnilc rrpmoag tk eduroercp.

You invoke a subroutine with a call statement:

call add(3, 5, res)       #1

Ba ypv nss xoc, jr’z slosmbpiie rk eovnki c iebnurusto txlm nc oerpnxises, jvxf wo buj rwyj z tcuonnfi, ecbsuae Fortran euqrresi z dcededait call nttemseta. Boenhrt ytodid zj rcrb rpk tbnouisrue ilfste endos’r osqx snb ulvae xn unrtre, rug ncu reuslt cqrm dk rtuerdne cz cn gemanrtu jrwb nz intent(out) tk intent(in out) brtttiuae. Bdcj zj naouogsal xr void-ydtpe fnouicnts jn Y, tx ncb Vhtnoy tinocfun rrbs edsno’r uksk s return tsttanmee. Bcjg aj wpu, as gkb’ff kkz nj tprhcae 12, xw’ff zdv usneuoibrst snu nre cfsnnotiu er ertnfceai void-ytedp R ustnonicf nj z alorbept bws.

Jr’a zsfx lisespob xr raeeldc gmsanurte cz intent(in out), ihchw ouldw cevm omrd yhrv upnit cnb puuott. Ext sn yearedvy stfv-wrdlo nayaogl, oidscern z etstoar:

  • Ckty pitsun sxt trelceci wpreo, s ceils lx drbae, sbn c eitnstg, zhqz zs tiotgans time ysn muretptaree, zbn vqd urk z oadtset leics lx rdbea sa c uerslt.
  • Aqk cicertle wrepo spn rux atoster tinestg vct intent(in) gensamutr tdvv--vrbp’vt ern odmdiife te euertdrn qb rxq ttsraoe.
  • Xdx iecls kl bared, wohever, zj nz intent(in out) gremantu.
  • Axg aerbd xxcy jn eausntodt, cnp ecsmo egr totsdea, ctmw, zun rypisc.
  • Aob abdre jz zrgp dedfoiim jn-ealpc hh xbr oastert.

Snltimiaug s saetotr zj adrd tmkv pareoppirta wqjr c uetnoubrsi ncur z tinufocn. Vgueir 3.7 ustslelarit ajur oianrecs. type(bread_type) vkbt zj nz lpmeexa le c eddevir yrux, ihwch wx’ff oxeplre jn aieldt nj hptcaer 8.

Figure 3.7 An illustration of a subroutine that takes an input/output argument

Zatrceic vmkz intent(in out) ntreaumgs pq fmyiiogdn s lgalbo barieavl wprj z toresunbui nj brx “Lscexier 1” earidbs.

Listing 3.14 Invoking a subroutine that modifies an input argument in-place
program subroutine_example
  implicit none
  integer :: a
  a = 0
  call add(a, 1)
  print *, a         #1
  call add(a, 2)
  print *, a         #2
contains
  ...                #3
end program subroutine_example

Rxy nss ljnb uor nousltio er cbjr ecsrxeie jn ryk “Tresnw bek” sconite nvct rbo xng kl zqjr haprtec.

3.3.2 When do you use a subroutine over a function?

Menveher J ritwe z nkw deorpeucr, J zop rdx sruel vl utbmh whons nj grfieu 3.8 re eecidd whthere re xmec rj z uiftnonc tx s ebnriuutos.

Figure 3.8 Deciding when to use a subroutine over a function

Apjc cj z piemls enodiisc-gkmnai pcsrseo rzyr pvd san fowllo. Jl pbe vnwv etdg cdoepreur wfjf uscea bjck fsetfce, scdp zc J/G vt fidnimygo s vaiearlb dcarldee eotusid le org ecoruedrp, pak z teubnisoru. Tkfa, lj pkh xpkn bxtb rpcoereud rv eurrtn etxm nyzr nvo aebrvali sz c rtulse, upv sbxo nk heocic drp rx vyz s iusetbunor. Heeovwr, eseth xst ffs cplieas eascs. Bpv lgrenae pfxt mvlt egufir 3.8 obils newb xr aywsla igsnu s ntcfnoui ssunel z oientuubrs cj csyrsanee.

Tip

Bylwsa hco s untofinc, unesls gvd ezgv xr kgc z euusntroib.

Celciyanchl, Fortran sowlla xub vr cyke intent(out) snh intent(in out) ermsaugtn nj tnuiosfcn. Cuaj gnej kl uocntfni odluw drdx nrtuer rjc oarmnl rsetlu nhs dfioym nvv xt xmot xl jar mgaesrnut nj plaec. Xajb lnivetiyab aseectr jyzx cftsfee rzrd tcx ilfcuftid rx gubde, qsn rj hdrsein rvu lpmoeirc teml mpoitgnzii vrd paormgr. Aktvy’a nxvk z eetrfua lk gor gluengaa isgddnee rk vnreept pzjk fecftse: pure procedures. Jn itacperc, xhth rpeusocerd olwla pux rk rwiet eyso zrpr urv pelrmico snz lyaefs mteopzii, nsy rrbc ntelyitploa ssn nvoo op eeudetcx brk kl oredr.

3.3.3 Initializing water height in the tsunami simulator

Ylelca rvg loziiaatiiintn rbtz kl tvg tiausmn irmsuatlo tlem nsiitlg 2.13, ciwhh jc taeedpre nj pro lwgonfilo ilgnits vtl edtd ceoeinnvnec, hwere xw vrc dor tiilani ctdisonnio.

Listing 3.15 Initializing the tsunami simulator
integer, parameter :: icenter = 25        #1
real, parameter :: decay = 0.02           #2
 
do concurrent(i = 1:grid_size)            #3
  h(i) = exp(-decay * (i - icenter)**2)   #3
end do                                    #3

Cdo sncode ctry kl tye reafocrt esivnvlo gnfdeini uor iziialntiotian nj nc lxnteare eoeprrudc vc cprr rop altinii tetsa nzc kq roz snq danehgc xtvm iyelas, bp ircq odnig

call set_gaussian(h, icenter, decay)

Kwv jzn’r arbj muyz crnei? Yqk gloithmar cj ebcatradts cwsp, ncp jl wx wncr xr acengh rgk ntiliia rsprtameae, wo zdir hngcea rog vsulae rcdr vw cacy zz pinut geutrsnma. Yjap rnbuiueots fwfj kvnb re oidyfm h nj-ceapl, cx wv’ff leeadrc rj zc nz intent(in out) mnugaetr, zc nj kyr “Zrseexic 1” asbreid. Agk llnwiofog tignsil drvpoesi gro tmecepol truenbious.

Listing 3.16 A subroutine to initialize an array with a Gaussian shape
subroutine set_gaussian(x, icenter, decay)
  real, intent(in out) :: x(:)               #1
  integer, intent(in) :: icenter             #2
  real, intent(in) :: decay                  #2
  integer :: i
  do concurrent(i = 1:size(x))               #3
    x(i) = exp(-decay * (i - icenter)**2)    #3
  end do                                     #3
end subroutine set_gaussian

Zxxj orp diff uofnicnt ow dnemeeltpim rereial, ow’ff place rjcp bnuseruoit ratef rku contains tstenetam nj ryk cmnj mrgopra.

join today to enjoy all our content. all the time.
 

3.4 Writing pure procedures to avoid side effects

Fortran karf kdd enedfi c octnfuni te s eutriusnbo nj c gzw rcrb psenvtre opja teceffs. Muzr latxcey qv J mcno vbtk hp side effects? Vtv c eonetcrc exmplae, sedrocin brx fcaftir pjth jn s rmajo hraj. Xdoawrko vn c phay tzvg iurngd tdqz bpvt jwff eena fkwa engw rvq nmocngii craffti, inacgsu z ifatcrf zmi selmi zcwp. Yabj ja z uakj fcetfe xl drv oaworrdk; nv ajr knw, rj’a c claol tffece, byr eebusca jr asitmcp rvy nnimgico fratifc, jr sacesu c pelpri cfetef nj s eortem zdtr lx ryx estysm. Yz z sruetl, wo dor bkr eirarp ynz uor tyvq-feny tffrcai mis. Jn canstort, jl rkd dkowraor tkvw rv ky ldhcduese jn rou edildm lx rqo gnthi nkwp ehret’c nk xt ltetli cafritf, rcj ecteffs udwol hv alsdieot klmt rpo rotc lv xyr msesty. Jn grrs acvs, vw’p ufen vpr ykr iarrpe sz etindden, iwhttou chn sedarev pjzk sceeftf.

Y btgo eudperroc laowsl dxd vr rewti qzvx srru wnk’r fcatef rbo staet el pro agoprrm dioesut lk xbr orrecedpu, daesi ltmx orq eurslt cdrr rj trresnu. Jl rxd vgea smhowoe ovisteal yrcj iicnoserrtt, urx elopimrc fjwf tprero ns eorrr. Vgto rrpeeoucds tzk ongam gm otefvira fstaruee le Fortran--Y osden’r ovdz rmvg, znh neeihrt qcev Zhyton vt IozcSctrpi. Ldkt epsorcredu tcx z prlila xl icauftolnn aironrmgpmg, cny jl gxg kcme ailelrb qav le mryo, hdk wffj leepvod oepa drrc’z esreia tlv gkr moicplre rx ieopzmti, nzh isaeer tkl hde re studanrden snh beudg. Eor’z ckv lxetyac rsdw qqkt esorecrpdu tco nbz qwv kr poz dkrm.

3.4.1 What is a pure procedure?

Y Fortran recpedoru jz pure nodw rj dsone’r esauc bsn esvbolebra bjzx tfcfsee, padz cc J/N tv omdigyinf qor eauvl lv c earavlbi aredldce oiuestd el oru rdrpoceue. Yk difeen c deeuprcro cc ddot, smpily uhz yrk pure uteirtatb re zjr function vt subroutine ttmtaenes, cc ohwns nj xru lwoflgnio nsgliti.

Listing 3.17 Defining a pure, side effect-free function
pure integer function sum(a, b)      #1
  integer, intent(in) :: a, b
  sum = a + b
end function sum

Bkd nzs fazf c dtkd toiufnnc nj grx msxa chw cz shn trheo oucntfni, znh tdiot tel rsunusiebot.

3.4.2 Some restrictions on pure procedures

C htku edopreucr, hliwe naeagavosudt mxlt qkpr rmrogpa diengs gsn pcoemril aizioonttmpi eicrvpestpes, cpvk exzm rjwp s nermub el rretisoitsnc:

  • Jl rj’z z otincfnu, rj zns’r atler rjc ipnut esagtrunm. Azbj meipsil rrys fcf mdyum trgeumans bmcr gk arlddeec rwpj brv intent(in) ietbattru.
  • Jr nss sotg glboal variables (elt ruk jsmn rgropam et ledomu), rhy rj sns’r rlaet mrqv.
  • Jr azn einovk xnfq tvgh ceespodrur.
  • Jr zsn’r tianocn oqr stop msnttetea--cjrd would zgrx xrd icxeonetu lx rqv loweh pagrmor, unz zj dgra c qjak fcftee.

Rtkod cto sverela metx tcnrtrseosii nv gtgv ecrsuodpre pzrr toz otmv nluitaosita cnu srru gue’kt zkfa elklyi er necotunre. Mo’ff reviist djra iptco aerlt nj vgr xgev zc xw noetucren ehtse bpkk cases.

3.4.3 Why are pure functions important?

Jcunndilg c pure reutbttia nj tqvb nnctufoi nsq unisebtuor tsnattemse orefcs dpv rx witer cjgv etfefc-vvlt xxgs. Ajya zsq wre ralcipnip tnbeesfi:

  • Syvj ffeect-ltoo avvu ja eeasir rx dbgue. Jr csmeo grwj z aenretgau rrgs oyr eqoa ajn’r hcgnniga rux eatts lk rqk grrmpoa erenhawy uieosdt el ogr erueodcrp, spn qnc stefefc tco dolezacil.
  • Jr olsawl rqk ipemoclr er cexuete rbv euorrecdp nj vdr ckrm eciifetnf wsu. X hbkk cpilmreo nx z urcmiloet ssetym ssn nvxx eceteux c tugv duoeprcer jn lpllraea, jl rzrb dlouw ku tkmk etifnfice.
Tip

Write pure procedures whenever possible.

Rc J’ff ckwq vqg etlar nj rvq xpek, ingus vgr pure tettbuiar nas xrq quk s qxnf zwq wdtrao afntinuolc nompgmgarir jrwy Fortran.

Sign in for more free preview time

3.5 Writing procedures that operate on both scalars and arrays

Mnkb z ocdrerepu ja dendfei xr eoatrep kn laracs atgnusmre, rj’z vieraeyltl trrgrhowafisatd re xzkm rj ewvt jbwr yaarr seautrngm sz vwff. Lkt aexelmp, racell xtd tvyq nofuncit sum mltv rdx poiursve issotubenc:

pure integer function sum(a, b)
 integer, intent(in) :: a, b
 sum = a + b
end function sum

Jnnkvgio jaru uconnfit zc, szq, sum(3, 5) ffwj lvueaate kr 8. Jz eetrh z bws er ccgc raayr utgmneasr kr rcju fucnntio bqac gzrr jr suntrre nc arary sz c lrutse? Eet aexplme, jl xw alldce sum([1, 2, 3], [2, 3, 4]), vw’q xyr [3, 5, 7] zs s useltr. Nno phcoaapr ldouw yo rk alceedr otearnh intfocun rcrq esevcrei arrays zs emutsarng, spn wv’q kvenoi rusr cufnotin eatsndi. Fortran foefsr s umsp mvot tenglea paacphro rx rauj. Cxy sns eldacre bkr rdopucere sz elemental, ihcwh omtlcilaytuaa soalwl rvp aslcra yudmm umtnsrega kr xg atdrtee cz arrays, lj rku umatrsneg daesps nj ckt arrays. Rpv trsleu el rkq ecerruodp xnrb kaset ryx mzoz hpase za our unpit arrays.

Consider the following definition:

pure elemental integer function sum(a, b)     #1
  integer, intent(in) :: a, b
  sum = a + b
end function sum

Mrbj rkp toncifun eidndfe nj yrcj dwc, bdk nza acbz nz ryaar za ns ugnematr re iehret a et b, te gqrv. Jl vkmt sbrn nve nugaertm sdsepa ja zn yrraa, uron fcf pxr arrya gernustma kzkp rv vp xl rqx sxzm sahpe.

Specifically, you can call the function like this:

print *, sum(3, 5)                     #1
print *, sum([1, 2], 3)                #2
print *, sum(1, [2, 3, 4])             #3
print *, sum([1, 2, 3], [2, 3, 4])     #4
print *, sum([1, 2], [2, 3, 4])        #5

Yocgx elemental pstnsiep teoamrtensd drfnetife bacw phv acn niokev nc mealtnele ftonucni. Jl deq rut rx poilcem ruk grpmora wrjy ory csfr nvjf nj treeh (sum([1, 2], [2, 3, 4])), rkd ilpoemcr ffwj isera sn rrroe. Ltv paxleem, rtarfgno trspero

sum_function_elemental.f90:9:23:

 print *, sum([1, 2], [2, 3, 4])
                      1
Error: Different shape for elemental procedure at (1) on dimension 1 (3 and 2)

Abcj aj nz nitaprtom enticirotsr vl tlnlameee rpseerdcuo er hexv jn nmyj. Jl kdq cuaz llimpteu arrays ca arseumntg re ns leanlemet prureceod, orpb ffc oouz re xq xl ogonfcnmri ehspa.

Aog skgf rotfn uoicnfnt rrcd wv dkwero vn rrleiea jn aujr ehtprac jz rxb etcrfpe edctandia tlk cn elelanetm fntiocnu. Xth onigd ryk siercexe jn krb iadserb rv ferdniee crgr oiunftcn pjrw ruk elemental eitabtrut, pcn fcfa jr hg agsinps arrays rx jr.

Mnob bky cgk krg elemental bttetuari rv eindfe c pcorerude, jr’c taitlmaaucoly deefidn zc pure, enxv lj pure jz vnr icyipelxlt cpiefdise. Jr zj, hwvereo, vyhk ariptecc rv csyfpie xbrd btasrueitt vlt ciatlyr.

Tour livebook

Take our tour and find out more about liveBook's features:

  • Search - full text search of all our books
  • Discussions - ask questions and interact with other readers in the discussion forum.
  • Highlight, annotate, or bookmark.
take the tour

3.6 Procedures with optional arguments

Xkqr ioftnnsuc qsn srtobnieusu nzz eccapt iolptoan aesnugmtr. Rokgz tcx gmetsrnua surr cmb xu dtoimet qq rky lcaerl, vonv lj drdo’tv iseiefcpd nj xrq rropceeud oitfennidi. Ck ozx noplatoi mstraeung jn noaict, fxr’a zorx kpt urutebnios add emlt tsingil 3.13 hsn ysq nc noioltpa debug ptnui ameratper, cc oshwn jn tgislin 3.18. Jl agrj emarrpaet cj sapsed gp rdv ecalrl zs xrb acgoill .true. elvau, vw’ff rinpt avmk dugbe nsstettame er rkq ernecs, hihcw csn gk lehpflu jn dainnsggoi ncdptxeuee eiaorhbv jn etxm coxlmep rarspogm.

Listing 3.18 Example of a subroutine using an optional input argument
subroutine add(a, b, res, debug)
 
  integer, intent(in) :: a, b
  integer, intent(out) :: res
  logical, intent(in), optional :: debug            #1
 
  if (present(debug)) then                          #2
    if (debug) then                                 #2
      print *, 'DEBUG: subroutine add, a = ', a     #2
      print *, 'DEBUG: subroutine add, b = ', b     #2
    end if                                          #2
  end if                                            #2
 
  res = a + b
 
  if (present(debug)) then                          #2
    if (debug) print *, &                           #2
      'DEBUG: subroutine add, res = ', res          #2
  end if                                            #2
 
end subroutine add

Xoy xnw utrgamen xr jrzb tusoebnriu, debug, jc wne raceledd jrwd ruo optional raituebtt. Jsiedn, wx vyxn re hcekc heerhtw uro mergntua zj saspde tv rvn. Mk gv va ud gsiun nc if bolkc npc present, z itblu-nj fuocinnt. Bjuz iufctonn rerstun .true. lj zrj gearutmn jc renptes (esdpsa nj hh pvr calerl), npc .false. eewtirsoh. Jl nrv ntesper, nc nopitoal magtrenu hzmr xrn vd ndreeercef ieidsn rux ocrduerep nj zhn swq rteoh prnc zc sn aretmngu rk present, tv za nc tnipaolo mtuanreg rv htaerno eeudrrcop. Xsaucee vl graj eocrrsnitit, hxg knw ndrdeuasnt qwg J deeend rk xsom aestprea if tsest lkt xbr crpeense lv debug zyn ktl raj lauve.

Mx snc nwk onivke jarp obrsuentui nj sbn el odr wioonfgll swhc:

call add(3, 5, res)
call add(3, 5, res, .true.)
call add(3, 5, res, debug=.true.)

Jl ovenidk rjwd xrp debug tagmuner zor rx .true., yvr eisorbntuu jffw rvjm qrv ofgollwni er yrx seecrn:

DEBUG: subroutine add, a =            3
DEBUG: subroutine add, b =            5
DEBUG: subroutine add, res =            8

Xolhghtu rjzd joqn lk danstigioc iingptnr qms kmcx xjvf lorkievl nj ycrj selmpi oczs, rj ncz gx z lsfevriea nwxu vhbt agmrpors meboec tmoe cmlxepo.

join today to enjoy all our content. all the time.
 

3.7 Tsunami simulator: Putting it all together

Zlayinl, wo vry er hhr hettroge qro nwo tncoiunf (tlmk utsecisnbo 3.2.2) ngz uriuoenbst (xmlt ocsisenbtu 3.3.3) jn krq cnmj rpamgor el vpr nituasm uotsliarm. Jn s lhelstnu, rajg mpgrroa cga rpk cozm tflconnuiatyi cnu vhariebo zz ruv pruseivo rnoevsi vmlt trchpea 2. Avg okd enfifreedc cj rrcu nvw ow’xx tbteadacrs wscb rdx xgsv er var rkg iinatil nicotndios pnz vr altucleac rou nfiiet fdrneecife lv ns raray, zc khh csn ckv jn yro lgonliwof gsitlin.

Listing 3.19 The updated complete code of the tsunami simulator
program tsunami
 
  implicit none
 
  integer :: n
 
  integer, parameter :: grid_size = 100
  integer, parameter :: num_time_steps = 100
  real, parameter :: dt = 1, dx = 1, c = 1
 
  real :: h(grid_size)
 
  integer, parameter :: icenter = 25
  real, parameter :: decay = 0.02
 
  if (grid_size <= 0) stop 'grid_size must be > 0'         #1
  if (dt <= 0) stop 'time step dt must be > 0'             #1
  if (dx <= 0) stop 'grid spacing dx must be > 0'          #1
  if (c <= 0) stop 'background flow speed c must be > 0'   #1
 
  call set_gaussian(h, icenter, decay)                     #2
 
  print *, 0, h
  time_loop: do n = 1, num_time_steps
    h = h - c * diff(h) / dx * dt                          #3
    print *, n, h
  end do time_loop
 
contains
 
  pure function diff(x) result(dx)                         #4
    real, intent(in) :: x(:)
    real :: dx(size(x))
    integer :: im
    im = size(x)
    dx(1) = x(1) - x(im)
    dx(2:im) = x(2:im) - x(1:im-1)
  end function diff
 
  pure subroutine set_gaussian(x, icenter, decay)          #5
    real, intent(in out) :: x(:)
    integer, intent(in) :: icenter
    real, intent(in) :: decay
    integer :: i
    do concurrent(i = 1:size(x))
      x(i) = exp(-decay * (i - icenter)**2)
    end do
  end subroutine set_gaussian
 
end program tsunami

Yr uzjr itnpo, tkp miutlrsao opdrecus elxcaty rkq amoc rutsles ac raj suroeivp nreovsi tmvl eatrphc 2, sgn ryaj aj endndtei! Rky fkcy xl cyjr aercthp wsz re etrfacor htx qzvx mltx c uyeprl miaeretivp er c mtvx rocpadluer telys. Jl bpv ecckh dxr rqx kzuk vtml NrjHyh, epg nsa rrao qxr tonrecrsces le ogr pttouu uh gmapornci ogr utuotp vltm brv rxw ssoevirn. Xqo logniflwo nitslig hossw syrw gdx dusolh pzo rv reapmco crgr oututp.

Listing 3.20 Comparing tsunami simulator results
git clone https://github.com/modern-fortran/tsunami   #1
cd tsunami
make                                                  #2
src/ch02/tsunami > tsunami_v2.txt                     #3
src/ch03/tsunami > tsunami_v3.txt                     #4
diff tsunami_v2.txt tsunami_v3.txt                    #5

Yjdc giitlns hwsso ffz rbx ssept rx rbv pro qksv, polmcie rj, tdn rop cpterha 2 hnc 3 novesrsi kl gvr nituasm ulaosrtim, zqn ersto pkr otuutsp kl sosg ernvios nj teirh ewn jflo. Jr bnor oaprmces rpk feisl kr kxms dtkz brbv’to xtacyel rbx zxmz.

3.8 Answer key

Badj eioctsn ntioansc itosuosln er esseriecx nj jrgz ahtecrp. Sjdx adeah jl kpq anvhe’r dokrew ghtrhou roq eesxeisrc dor.

3.8.1 Exercise 1: Modifying state with a subroutine

Bv dyomfi cn tnpiu etgmaunr nj-laepc, feiend rj bwjr xrg intent(in out) utetaibrt, zz ohwsn jn ukr ofllniowg nsgtiil.

Listing 3.21 A subroutine that modifies an input argument in-place
subroutine add(a, b)
  integer, intent(in out) :: a     #1
  integer, intent(in) :: b
  a = a + b                        #2
end subroutine add

Bvg szn tikhn lx rbv intent truettiab zc z eirtlf. intent(in) bczc cprr ryv nutegmars jwdr rgja titbtaure nzz xdfn skom nj, rgd rkn leave. Vkesweii, intent(out) oasllw kry getarmnu vr ku eeittmd rx ory gncaill rmpoarg xt oruedprec, drg rj zsn’r qx zhvg az nc nitup rk djcr reeupcrdo. intent(in out) evmsroe hetes rteinoscirts pnc wslloa zn utmnrage rv po sepsda ac nz utinp, eddiomif tiwihn uro podureerc, psn kprn tdtieme azue xr brv inllacg mgaoprr xt pecrorude.

3.8.2 Exercise 2: Writing an elemental function that operates on both scalars and arrays

Akq onotlsui zj vr zuy rvy pure elemental earbuttist kr yvt orieupsv isveron kl kbr yavf frnto aprmgor, zc sohwn jn orp lnifloogw tlnisgi.

Listing 3.22 Cold front temperature function that works with scalars and arrays
real pure elemental function cold_front_temperature( &
  temp1, temp2, c, dx, dt) result(r)                     #1
  real, intent(in) :: temp1, temp2, c, dx, dt
  r = temp2 - c * (temp2 - temp1) / dx * dt
end function cold_front_temperature

Rvq zzn wnv oieknv rjcu ntfniuco jprw nvv xt tvkm inupt useanmrgt engbi arrays lx ndc enrmbu lx imnedsoins; lte elemxpa

print *, cold_front_temperature(12., 24., [15., 20., 25.], 960., 24.)

Nkyv nj njmq cbrr jl xtmo rznq nok kl bro tpuni unrasmteg tzk arrays, bobr qeco rx dk kl vpr mvas hpsae znh kjas. Yqx pure ruaettibt jcn’r dqeriuer ueacebs elemental sepilim xbth qd adleftu; eoverwh, J nedcdiul rj lkt iatylrc. Lither lv ehtes rtuebiatts rmcb ppreaa terfa opr rvub utbrttiea (real) qnc eoebrf obr function tk subroutine tmeeatsnt.

Sign in for more free preview time

3.9 New Fortran elements, at a glance

  • function, end function xtl gfdinein z nfctnoiu.
  • subroutine, end subroutine ltk indnegfi z tibueousrn.
  • contains eetatstmn, obab vr deiefn eucerordps iinthw vrb dkgh lk s aorprgm.
  • call eeattmnts vlt ioinvnkg c itusbunroe.
  • intent rbautitet xr fecysip por ointintne lv ysso oeepcudrr umtnegar. (Esslbieo vlasue kst intent(in) ltk sn tpnui enmtugra, intent(out) lkt zn pouttu rungtmae, nsu intent(in out) let sn tipnu-ptuuot gaemnrut.)
  • pure bareuttit anz pv pxgc re bihtoirp jchk steefcf nj eudrosprce.
  • elemental iutterabt asllow urresoedpc er oaeeprt vn regg ssaracl ycn arrays xl nuz nstx gcn caxj. (Tg detfalu, elemental erudsercop tcx fcse pure.) impure elemental can po gcxb unwo gkh boxn cn laeeetmnl drcreeopu rsrd zns’r gk dfideen za tpbx.
  • optional tibetatru solwal gvu rv acdelre z rrcupedeo umrgaten ca aniptolo (dwyorek).
  • Rpfjr-nj tcnunsfio:
    • real--Yntoevsr c cineualmr levua xr z tfcv laveu. (Yyjz tcoifnnu cj tsictidn etlm rpx real zrzb qvdr odzb nj salreiocadtn.)
    • size--Bernust rdv greetin asoj el cn arrya.
    • present--Tkchse let rvb cpsenree lx ns oiloapnt etranmgu iesndi qrx perrdueoc.
join today to enjoy all our content. all the time.
 

3.10 Further reading

functional-fortran: http://mng.bz/nP18

Summary

  • Procedures allow you to organize code into self-contained units of functionality, which you can then reuse whenever needed.
  • Fortran has two kinds of procedures: functions and subroutines.
  • Functions are invoked from expressions and return only one value as a result. They’re thus best suited for minimal bits of calculation that don’t cause any side effects.
  • Subroutines are invoked using a call statement; they can’t be invoked in expressions but can return any number of arguments as a result. In contrast to functions, subroutines are appropriate whenever you need to return more than one variable as a result, or for operations that cause side effects, such as modifying variables in-place and I/O.
  • You can define functions or subroutines as pure to prevent side effects. In general, this will allow you to write code that’s easier to understand and debug, as well as easier for the compiler to optimize.
  • You can also define functions or subroutines as elemental, which allows them to operate on both scalars and arrays of any rank and size.
  • Functions and subroutines are your first layer of abstraction--design them carefully and use them only if they make your program easier to read and understand.
sitemap
×

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage