From 80d0271864521f14cc1ebbba23a96727fd67d497 Mon Sep 17 00:00:00 2001 From: Fabio Roberto Vitello <fabio.vitello@inaf.it> Date: Wed, 13 May 2020 14:50:19 +0200 Subject: [PATCH] Wrapped code into functions --- aprod.c | Bin 15466 -> 334336 bytes cblas.h | 4 +- lsqr.c | 2532 +++++++++++++------------ lsqrblas.c | 66 +- memRequest.c | 0 solvergaiaSim.c | 4823 ++++++++++++++++++++++++++--------------------- testMatrix.c | 63 + util.c | 343 +++- util.h | 11 +- 9 files changed, 4413 insertions(+), 3429 deletions(-) mode change 100755 => 100644 memRequest.c create mode 100644 testMatrix.c mode change 100755 => 100644 util.c mode change 100755 => 100644 util.h diff --git a/aprod.c b/aprod.c index 1e1507b99a8fa4a9dde4c0bf9e86345b453d4c1b..1b5051602a3d1dce65e88a4042c447b1026529ad 100644 GIT binary patch literal 334336 zcmYc-Ey{PTNDNKS*Vl_rPRdCv*2`d^GB7YOFf%bxU@$N+FgG&=(*{Nmz5xgrnHeY; z8k?D#nHw9KnHwt@7@C-x8ZsytP}v<=jVmoKNi1S8Fept*#VQXIEG|h*OM`K+&>)W( z7(hG+qOm9$ltQdx><ml{48DoU3jV<g5eiTM5@X<GU|=v}U|^_YU;y(s5a$EOkdPp# zN|25P3=9kcP(F-eWME)`ic2Nu=jtUE6y&7p<s=rDloqF^q$HN4DhC9E6rYOO8V91? zM1E+3=uu4F5J1ZRG|K%9pnQ)n|C^W^o1*7`V-wTS{7>DO#%`LvmI5^1xfB!>RDx2= zGK(|w^Q;t%%#9UP6jWRiOH!>Aj0_CSbPX(Z4NMdaO|48Vtqe>QbPdc63=}kc^Ye5R z3``V)QwzY#G!<01Kt}0O1%ONn$;d2LNXyJgRmdz>C`c?SQOHkIaB}tuR?u+DFU?EQ zb<WQ#E-6aP%u7vC@JUT9E>Q?BEKMv*E!NZnJH<J_pt2}4J)=ZH!&wvTNCn@_<c!4B z9EAWq1-GKi)RdgWyp+@;9R-(EkOjG^d0<PN^K%PIOHzwKt_V)fOwCJ9)lmq|%PdPR zD$Xpa1iPasvm~=PL%}&er!+SyGf_vuIWaFWB~eeoF(*d>Y-=${dr@j}YEfBgik^b2 zZf;^`j+KH<Zb6zua<N`%QnFrhqMaT{6$pcU2J&%HYN|qUep*R+Vo|EKLS=rbLULlB zLQ!f;W^qYTW>RTMszPRoLSkNuetwZcZhlH;TBSl}3CM_2kY^N1GEx;vQj2nnLGA=` z-2Flod{T>xQ;QVbQ}a@b5_1#+N|SOjlNEe2lT-7GQxy`yZY=-_7H6cUC?r*aO>qM` zB^c@y1vgNjCzfR9=UFSHW|m~67Ab%OBtK8VNY4;z8ORw>Q*{*bixe~xOF&*IQphg= z>C{w6%&Sz$Ni0EV#s~m}KT{Mk^S}<t$S+7$D9K1H0r|W<GbcwODOI7gI5n*_M@J#4 zv_v7?GsMF`Gz4V3qhF*#xMNU|qhCm*wL*DjNk)EYi9%{wD#WPF+=86U)D(sC#G<0a zJV<2vx&}FWIQoS+I(hndhD3r)$uClH^9=EG4Gvat^AA#RR0wbk3h{If^>GYR2nY=d z@DFy?Q&0#_1vx8K0W*X_W}pRf8aTR&QWa8COA<44is2rQ%r8|a&d4v#Nm0m1EK5}= zN=;79EK5yMNK{D9F90VuywM1<3mWDMi8=Xs>0n=jvx>DsW|~4?eu<7kc~NFbszOOV zI6P4z7Ni{!w>k=*dC7V@3Z{k%ZbgZC**Tec3c)2h3T~NcB^e5CIr;fTItott#U-Hp z@9U^wU}R`$plfJsU<fiNG}sYDQKbyf<<ipU($`W185jd92S5yGCm+XPg`CW!qQs&~ zg^bk1l++?{A)yCS&83`~mY0&6rVtNS7w^HPoRXTBnU{(X04V{f@b?YiQqIgv&M8ev zRj|p=Ezrxb<5Et|OUX>*LXyZ$EXe@Nz?Bx4q@<*#fyCg3`@6XXyM}1^=_q98B}Zr~ zXlOuaI|Ty;dj$mp1uF#&4L?l<T?Io;1uX>)U5LD<CKp#~UTLlZ#IgQCF0MhKW>~c| zs68H(U+$Zjm0x6QXke(L02Xr2&w&XU)mkI#4GD7e3kD@h1&C(9{E(u=ykc8JLzrF| z-w1A2UKUKuxYnABt1Le=g$rCK#HS=y6jW*?gNj#$%)Al>KOF@KCndi$DJNASF{dCS z5lu`hLI)H-AoqhYL<2}SC@gdopjx#eVfvs_k(y|BgOWVdZg5%#sY7>wRs@<U5jqMe zw&S!76h$Qpc_oR(*~PX7AiKFBYGGba$uEK0PNc=i_Ch=jF;D@!S0R!x+wzKXjiA<% z<XMp0kUfDMdBw?zIfTrF#vsHo3YftO3K(QF(^GTHpk`vE*!&_;6^a}T(A0vY5|KW^ zY0eQj`h1Z&e%MkG)R|C6qXe>o7K&LpDT#Otz~WJu-B2r%QcKVbfJ)$qO-O;Epsxil zU=+0Uxv)3629+pM`(H0Ur?{|4FPZA@Bdz~$2I~Ktn3#;V|EV4k*bE%x{eQ-TyW&93 zHdqv@2ckzYbwdCt|I;Y<6X^dNnwppznIZN6!TI0F#B4PGQ#Youo2IX&0Eu@{y$$YZ zJHvZ(`DqG1!GS>v<%yvFcTsVPLUK`RVhOlk2vV+~fapgfccam}wji~Mh^{-RI}h&U z79=KTC#I)bf#ekw6f#Om3as??%gf94;N4>Vy4->^{iNiaV*Sj#l++5njFQ|OaEB=* zBUPaQ)T_=b0k``>g9EvVnRz9Uae$;ssHwito_=s5xK~`PU{efbITV*9=B4EqrRb%m zl-hwu3XBaE981$dLj>kl3T~MoFT=XF`DqFzAeVzWAkZLF$WMaWmR6LX3$+j2=mirn zn~??>)QiErF$Jj4brg!r^5DUpSDKpy8EXJ*hY?g9lYtotra=K%T#{c<keQdRP*j?e zTC7l>T9m3#oC6vv$*ELG%qdANN`>~l6H8$31cyG@1Q-#Lky;7qu_mRaf<`EcOY%V) zp`Fb9qRjNnyu=)+C7=ObSbsjv+#H<5^tiYJ5{nXZa#C|Lt5Q=GKwV_lU`GY_#LPqm z-^^mrkd&T6sGdSnYI1UBVqT_#qn<)oYI1T$W@1Ucf{}rtF|^wU>&O+Cq~v5KfqG|% z&K+pjBrhFZEG07^LntXfKL=G1v;S9;nVX8HrXUkVK&iAOGe<8&38@>IlbM@YQVdeX zrLV7?nFi{C#>YDb1o*hd$8+iHD<~kGTb7#albNIsp+H*n^_5d|ic?XQDS^9cAX`Av z&~7WVvm50a<gZ|$XMpIS`nf6?>KTChcnXOHMfoWjpdLhSeoCs20=(mqi^R@@_t+|; zW8v(|=vb8IHMDW8Rg{RNRVz2Kq$sn(6O?Zu-7T$5&_JDYehw-ZB<Pt_nwPGlP+U?} znp~ogoS*BGSOOaM$OV;7Itrk`jxSNr%FitbPEFRd2897t1{XjEr5NSq7v(A_6s4Aw z7UdNyC=?eKm1rm=YH1lMXe%UvC`|>(SV}=rYI0&JXauVmq_ZSnAraI)Qphh$ElSJD zFW2MJ*9S=$87lZD7AY87S{k4gBp?+E)Ny)oNn%N6GPFm{1@Q&6bCv?_prdzdG`Xt5 z<rGxDI5{yV)fy~<(wnMEEy`E01tlG8aJi@eR;XaBkd~NKtdXdxpbcRqX+kt-rYUGZ zmDnnPG;4y*1QigFKm`jz)Pj>RNCt$VvJkymkbu`nRM3Z52p%Ls;%O^rB%#P5c$(H+ zwOm}#5CKIAS4vKPVhS`k;7L0VEkK}MNoa6XM90Dc2(BX&l-BeW+`{4&TwOfDBZ~_9 z`ufTRMTzOTi3<6-1)$Oj>|Ic)rI85=H*1AV1sjDtYlTd0ZA4I1L}$h-*g{54AYlRV zKG^B{`cz64`ugA^6_g68lgvP&39j)pz`lfsOfIAdfb;Vpd{7|<idql`Yt_&Kmo%D4 zMGd&nffND+3K(S5KqewE*lexP;-c`PY)y#O&}d9a%q@TjAnOLJS5ScJfXG8NXl3W+ zm*<6m#>#a-7U=6M<fP^)*eZYvg@XJdP@5;QSfLag05DBuVX4U_VD%t93UE!J8W5qU z3`I{lPCW`msR&KwD4HsQ^K-yu4#YAX7FD3=0kv&X5{pt?i;6%4wNO2YB?>v<36eZL z1qI*4O3?7RU#O3d9*XV7smMkpmgMK4gjN!|KyrRwP9`)pfMPbY1i{zWR{%9Mic&#s zGf+#TEU_pvF$vV#NGwWK$S*A^C@oRQ&&#QVv@1aRwK75NlKA}65{SJJv64K52rLQ` zK?OG!;pF_h6ineF9IA1MS729OTv=R_n(GU$+jJB_(T*H*iQu4v=Lyt0P+uP<oU;=1 zQXw%7@gb-l1XYe;Banqa5|9cKECus@K~bu6eqIVVNr5G>*Pf692vY7tGX&)Y1K2)& zeJBOa0N}oYLRw~CO0hzsLNPSWDpbHG8`AP~a`MYTX`rAeKPe|Qw;0m$M>WMzPa!m~ zxH304wWKIBSs}Hs6g<^bte~q4vZXjbrz}-L!BMM1!B!y&YCV(!$txJ?DfndOr6v|Z zQ+hFEDo_ERey~OY1at-poPBg*h8BZn&7ihJDX=lddI~Oyxdo{ycpagkprGIgQm+a2 zjfO&!0wk`Wu>_JLj5QQe5_1c*JQXy-YBdxLNHT>af0bu|dI*l7zE+|Fq<IHv7v(Ax z<(C(OCL<N{6p}%6p?SqR3Q1svdB`D?t6P?uTmmYR67y2PE(fat*Y}A<dI|~}pn226 z(!{)y%#zI1Vg*nsQIwjPqlXeSpfUw&KiD;yc_pcNDXA%-w3d{rkds)Ho(gtNaY15H zajKqzf@cZXqU2=I1ZWDflaeYGa#IuYz|*9~rAbBkr6r)5qU6M!9IzN@&Mhs!2-3kr zO|0M$hY;X8PC)}S5u2)`kgKDRr=w7zqfn`%0I8zjk%DY>c}8Y(hC*&>afw1fY7xj1 z@U$Evr=*qUC4*a=*s==5Vle5M2DVtiR>2U|!U0cPD=1Vd*eX;iXoGSKq;$nhSO|?q zNE$(zs{*7^qXaa4RFGess;LDnp;1Es6cLaZEmo)ihj=A8$};mn<$6J4QDSatNor9s zsK=L-Uy`AaoLHO+neqe`ogl}1rYRsfUZD~;2bu($V1jf(VY9c%8Hsu6pc144#Xm?U z80jb|R1jkV+&3U6fa@r@V_`9t3#lN%9ad1=t~|deySN}R88lC>kdj)QT$GuVikg&C z!F>Rbk(j|$lu@hz2`Wg&fCN!lW}-r=4mjkBOOuLI3rkb;N^&Z}JqplVZAoe#%&*Xt z1EoNgDEQ@rmS=z)e4u%7P!3ecEJ-a&EXgcORme>($;b!iiNu0}qWp@?+(gjaZw6>x z0i;C%Ga76dC@vv`5THqXs4@9@#R^5Kg{7I$9(_@2VsZv(Mmn_!H29&An4DZ%l$Z<| zZh@w+l+=P$P%ThgQk0*U4)P3S&K=au2gM$EECn=t1Fi=26chsT^NYYm07MqqhoIaC zE?e@8U<C`vb&jw&2CY9xP0KGz1+`_soiWg)KB$~RHl-lHxHvN@Cl%&jWI4C|B8Ak7 z#N2|MR8W&t0a`mL7=rU6ydKLeRw&Jbjfp^qm!SSF$}iW2`VCalq$wnVibIGqGeMDF zRH;y$o0yXWS_uIuo09W$3lbqgitHAUZ}UN30vP}<eH?Yb&PdKLDoQOb$j?gw1yNCc zImmPkQ1y|dpa~0$BuK*z>MD?nQd1O43qZD}<d>tTBXFF1=E3}1tY8REg+>qy;r^}w zm7A%F#hE#kpcM(Ao-S&lN0e5Of*&a;Li2J`i;ESKQcFM!Ju*R~ZMop;9AqZA(G6+g zL0t^;eO`VZr~`>Lu9H&1i6k{ep%}D&A+ZD$G@ya19PscHdO#K@=B6sRmL}(9rlcn3 zDS(=D3L2?;>3TY#K@d%BX#o)&3dZ1YC<3oK%F9<sD@sjG$<GB<Fh!|gFQ$UlRDkMU zg-r0W8CZD+^?{y(f=7ONY8hx*5y)d@i8-aIpjZQIfv)oam2t(zndzXVOQ1$DvKJE5 zK!KK6Qj(enssa=;5<wxEnx{~Zm<i6*AX7n+3`!CCX$p?mJOs+qh=L7lbtb4VMpTy> zsW}A-MXBkfIf+G?RVXPaGbcwE)RfKy*$)bJaMQO~2edAzpa`^-rUYa+$Q>m`rHE2R z0X`lIjo74Akh-$eBG8(jqI6Jw?3f2h=TN`E9RN=r1x5K~nV>2iHLrmzLwG0=<UAb( zXg!KlUW3LSQ;Tvl^FSpYq9{WS-y}$}0WuJj8%sf*Jb0>4N=?qsO@-!NaF)dux}f40 zvK|SXOY-tT>#-Cd1v}i4FpZG>mZnggpPQ<XnU`6TnV6%HT3iAtl`9P3c><gbGt(fg zBU=RnlsuB3m#UBqUL#acl%JdmS{+oZ0Lg+_+tUgPhI$Ing>0a5DYZB=r8F@IRuh37 zRb&8aODpJt+6e|Iu2ldvr$dWVAr(wXKB!e+23hI^=>~yX;whlkLJ_(~V?71OloU_~ zRREV=;AV_M3b;1_88=r*1a%e?b3lfIySEA;gDMOZv=vg|^*eHefu|>+bx|=i*bN}X zeqv@0s8gu`jZ;wD5|Vwuv74BagKSPoKG;8c3JM|l3R$Ho=@1_!rRJrkWtJ4{C={0# zfSNpDRSG4E*{Q_}*@m!sH9rp}x5EPk+9d%;UbYdEYEY2@>9#m(VGAqIGzCcHE2Zb> zrzq)w3o4Bw15E|k3O8`wky-@uGNc&ONP?GMpa@j(1Wit)Du4?-P~RCmreBhulUkIR zmkeq|m*nSw9R}*VgWG5DMh&PsM-CiFyy}2F3<||;BZMn5b2D=iiy#Z_K;fDO9@U3u z8EDL*7zSC*mXxZH3#y?ZZG{q0_6L<qpaM^!Jh2iKKt-u3rOA+ZD9JBL%uxU}wvdg= zECwkn1uas9H1CTPFntOdiUTLP;#5$<paAg<N|N@3W<W@B3=WUXVuj+;%o1<{0=4s? zF$pgJVRnI)BfAHrQwvn3Xe4RsgK1EVA!=fDBhg|W*{Fabuxr7kEU28!1U2Izr6XqO zU~8bEdoUB+*MYTpK;Z^Se~Ai3sh~BNDbRpX@CA1~lN3_Z(lSBoTT5~(Q3@MKf6rF| zsrgu};0S8Vg9|ZG)sa@31Bydr|A6aQ1z%8s0<N@j^2-%KO9(;jkj#=|h18r>&<a~f z-wvF%A?^Y-SxfSfO)AOAF9z3{j+#1<+z4uuC+FvtrGh$m;6zoFSdf{5)W!tYQOJgX zbBKbYmaj%8NFS&xQw1vUP<#q0Eg<zs1$d!tQYxak1FG;qK?sT+NSIZ@!W`KqKmQO{ zD^O+x_etS{7*MA}t9(!;0a>-00$$PxYc@E7rrYws4R=V$fU+3e4A4@ltkU$vl2qOF zqQsO;&<bT}^Iju49i?v!T@f4{>Fetg2y-Sl5FkRJdL}VX0ki-X91oBhH$P1Q$+C1% zSyKXv_Z(0s95q%zOLq}!9l-?)xTwM&F(ny^dEm%Haf@dfC?ORq6yz6Yf;%hVIjhW) zRB*N{N(GlvkW7H;Qc$ZHInWU<Nrt)_T16mcGQo{dP=NyKWg|*vWK+P7gocj>XeBY& zL!h!BQl5aClGw5yyc~ua2BpBk?UxUlpvgxW|A39WLDfMiuyRn52&u?H$qa1>1YBNc z<|(9P7AKb$7lTxQ(+7OK0@);Z(*tXZz%ePYNI^ltRzU$V00kLY20J4OEDe^$IUa>J z<^<M<AdrWkkevmx6=HFcf`Trn=}>`WuR;;bVu%Ys3X&3wv>@Z!sNHGsh%ML)kf}OI z`Kt+<sZ-Ea05_aKY%NGtS^<_o$s<t5+A2U)K<tL8Kyh<wPC*gaCQxvLi%(E71)2v0 zZ<GKv=+koY6G07O-GY43sBL0VW=TeFYDs1?vO!QA6%-WmA)Vpe#N-UnI1{9842oYp z1qJ^+h1~q&5(TJaF-jSQFro<TDo{O<1X|Q?sArI>YYxtbhI$4mx`t-pB04iK9kfUn zG|mQ|4#e&pgjYZv%+zF1W`vE#qlP+UfHyZYFEcl@DizcMOI3gkP$@v71T;{i05u0x z@1VEikevXU@rMi!A&bH?h^{VF6iR_Tp9>}xpe<}LCl_2^C?N7Cc(5Qd4|{hg53C2p zfIM^qAiY>nCkeY5kdZzGh180Y)FRNj2FUvV#H9Q(tm6ydPL~3TouI4^5(Z^scxDAR zUSNX{#tJCrL7k03X@E>YYIGRr86X=2@6)4>o?;lI0IIY=2^`X30(AsHH6*B}$jk$E zjuJ~iqbE8F;ARj?`xlE@`Dx%B2ugz>Gm8@Q(o+=-K*<4|TfvD}6Vi5agylIb#(;&u z#V{yP5|eVEi%b#~@>0`tGSfjW0<~OHlS@!)7O*~4!Ur@STm*GJD9eI_4Qw{3BMfp{ zN-Ah^6Ljhe+HFNO1k3|@2vpjD41tVyBDGxMi4Zx>g0-O%i2f*IXf3G{rH&+E0w@7t zR%qZ70OUf@0-VJ3RE50M)D+ag8dQgXc~G0d6)spasICLGgFypUkO&9)78GQ#a7K1r zQ90NYaDyE(I;sF(+nrgW04@(f{g!;t;AD|{F+vf{B#2&264bM{QUC{uf<j7uYB6Z{ zib85dK~83JCTM&V)Dr+L$U=4srZJ%XVvrGNNVlaRvA8(37_@r`)Ng}Vo{+ULpqxX< zIOsSc$Uh2+Sp0*mzf>a^JSPJg4*)w36mQ7mz<LS_PN|>`UXb=yDcVpHSPv=z8h_J; z4h(~urJzC?7MRGEmucjIEeE9%aI`=rp%mEAaw61JK-EBJYC-yfpzCBni3L<RppKlN z7x^F^3dN}!S|H~jnF5-5P|!;+(NoA%0QC$YWd>NlKt}=6>H@drafFFRZenFpD#%dq zSa}L)njsgw2N2Y61-T722d<C`nglOa0QDVEhe*M0LnR=)$v_iPuuWZQ;B|nYa8@Wv zO-n5TZ384&p8A6ZamzD{Qx!CF74&ja!M+4J4B|~&1p`fx7b_J~@<AyZIaW~J1LlF| zrxbEalQTej%|OFPC7HR<`K^-tB2Z2TZ4Cqsk0zE8li!O|OF#`41%={N1zQEk3IGL9 zP`f0t1Uy5d1Cjxij|3bB?aY+qmnLVVreI5lVE3aEpe{IcShWOfIk*M}*`BJ9l9`*D z2U_k2DsqZb!E<8-+>n&2kOxXYpx&S!$V(cAR(asi1+Bz@Ea^f`3Iq&<jmd$=)j)$T zpaHksg8aPHyb@67Ljj(`QN4xWfoBvz(<GUoaMZ}u1XZNPsU@I#29z+tg(?9@C@4Ui zRM1sX3dNb}xrrK?I+>aZ`U)iq&?PUpYbr?J9Z46cxtNC-aD-06Wa^e=5O7LLW@36i zsG$SX0_jGBVhGfiK%OH6@d=m)&IBc(nMz22WrC*vpjiY*a~GlzMuPO_D(HfW4X9pd zAp$lTR84`FV3A-H*kF)RV7+>Isd@_V(M)8|fL6kQ)FPGVj+g-o?<0Uq9atkMC9wpu zGz52qK{~*BpiXQmY;xUEPeB2knxOMj$j$*d1r29HJJqm(Hc)~~1a}e46jCzNA%mN# z;61{yVFxr5KwPjtZ9#J+sk&wg*fKR}@C&4p9wC8NU6K|WNuZoZS!jU$iZ?VM>z_~> z_>OrBr3D44MGD{rzo0H(a(-Tl1}J-If=fHl&`M%aY967u0BHjc3?lV#Kt%{_@k3H# z5iEj05rPeSLgs@(6S<%g9W-DL+7=F;8c6}oVS(4#f;PIN%w=OS3RW<Jaz4mm5dSEo zR)FRqia|qEIhnbHoC6-kN1KC!P9`ZNLnoCXgM#_sjrVvGDtMw0G!_DyyFzN+JA$eM zP*`J3L}Bq%a(*tT8<v?@k`L`ofSb|DiKQTu6-x8U6Z1e*L+M5N<phgL=xQ2_RuL>v z2;^UAN&*#R;IatPVgWTaQxu9pM-wELq~=sA5Db`-{Pa{%0|b=+;WKNg3OMHTh;*D^ zeo<~>PEI9god{@wA5ymy>TPgOkAN2q4Gh3tK|_6TKM-a&mWTlh1(&9$rxt_4A6#j| zmcfAKun^Dyv{f+F*Dy3N&;r|`sQ_x(gBFz+K>D%J;cr}{D{ymBP18c^y=sC@1TO|t zfG!4u`2?H)p}iUCG)*b!1cppVk0v=kFFCacH2n)Hr$KoeJ|cj%qYWyZbris*5-6QO z+z47g0!kMOpgtR<n$Cr`cNL1U7x*Rl;6>S>S+I;$SjvYN5TG?8pnhN?WS9pW_*k6- z4q+Y80DeIcIO9Mg7B&i$S(b`@Gzqdwlt8Ho3J!R$8ZmN<x_}5CUkC<?$p-2cTZKG* zBLzrmDNn^d`Hd}l5%!|9z~f=bIi<yrbxfcV1*xne)JB0j%R~z_a0MO>2lXkiCAB=z zKp^TUlN;#F6lmyy`tt=vpk;C?&_%b9l`62|cS24{R46XZ%>|vc081ip)AAtuuRspK z<}mPLUIhiHt>6H1%mW=KkeZ%aq>!Fj1}c3)@m!ReSe%~+&RDSe33L(-G{B)0SU(bB z0A+)wjtvw*wLQqF)QZI968O9_%vDgO7?fW=Qp$pCf`YEbBiN-egc=6w*QdglszN6a z!6PcLu`3+zhw4Wvob(hFKqajP$PitHBuL+(6fr?Zz#wqdsRIgE=s_ottP85LK_v$` zi-HOdSfJoA4wMZ*ZUa|CnZ?LO1?Ctbk$wbq7C|*5q!88vEq(=;porzPur<ROkb`LO zRQ=$cW{`CRpjDsXBVj<(xQK9qu1qUQC6u(&Ght`KfP)GaQUn6X7!*1Rkhum>vO}!; zaRhhqVQYV3p2HE&P*dP(6+B@|*mDF-gSB`u(gBg4Gl4n_t$ULUZ^MF}32FBc9B+Ws zP|$h?E%7846r?5=fv5Hfj?AF7UO=-Ypf(PuKm<3bi$MK!(BV0tMO7%1ZcyJKQ}E6i z(u!a3z&?R!H-#Dk%JA@ETxcsFT3my+%Ys))VlO>1OF(5gN_hw}3|da-ry-X`c#9$M z<_857gV5p&R1~@u<tL@)WtM`P8%4RG_*Ve6jA7n{dIy7owbDUGKpHr@Mfv&QQ?bB8 zrC_5VGFaOMNG3wsBZz5#&{{QO`Yo_&gklA7p$0CxG9fEnU~@DeqX^^$@KH*jW)V17 zf!51`3XFX4ib2pepY)OpP*;~wDFF#>=p24#9%Qlr+`i5)P0z@wgzR0*gU<&e`5%Sp zr~sP22Q4nIR7lB81CJ+`K>9A=st;mMZX(KpS`-r?oXotG%w*8ww!}Qh_$Fwi0X;D* zXn=AE%9=iiZWI#Q%K)tj$OCNy%q%WR%}cHXE!!*yZRiDU4~5Sp!99o^?BHd1c#~o> zyyyVuRZw3s1>CPiHU`C25Dp?+fKx4~&HyhX%*ag7fQDLrngZB<0w#fcnV6oK32J*_ z2|ApaA2P8?D4RjnLcuE#&=ipdXhNIdFdZm2!6#86bHT6~))WPe;?z{o@Gy9Z1_A$p z=L<E##cXCVV$l|;%LeM?gPIez3Q3@Xn~*{9$_Q3SAZtj3h6mC}K9*7kH8_y<L!uRh z1P2zlR6-s~1cjagbg%@ZLLonmfH|O`EP}0X1T}a;0;R>E)s7$oK&vfbO*EL#P~3sU z0T+MJ%nlk>hlFAtxO)ZJ!Jwd^0SO8MjsiEA^V3RF^FRYH;DQV^BL-R%19BdC-7GlS z5HJVSZ~{-XfY#Q6rVd~YYUq}N3iy-+vO(ZIYzl-DFDP_CH3P^&;Fv=;0x48rO!$&N zxZO|<s1#UvFnp2?w5lxyzF?pjJgNcJ09J{Z`NzhBs)SNt4WYr1bJD;Z2m#K;$ZEhx zszKynWD4kHF&%{z(3x903Mrr(0g};t63amykkk@|#2nC313CHSu<2>2kx&Y3QV?t| z2&MW%I321MN`bXF>pANw1SDoc_a^!3IqE6E&ZW?SOm<o+ID%4HdOmm&3AjdpY+*t+ z2W(glWS1MF*8v(0fT%^?b%t59IXe47=4cbat8$A$<CDILB^jxp#resJISTNz9xZef z3>7qd6N{2F6bvmbjIb1E1qFHvCdRtvhOj(^>{0?gcFci!)YQTlvP{lOAsD=63)vLh z{zdISfchbzeT5YI*hoRct28eapN9=CO?8b7EU|mpM^6Eglynq=^t|*GJQDMYL8m0T z=mqI1cxUD%gVwx*V#`f0L{GuHC_g;|)5T7S#hJ+p&`3_qNl#5G0`<X@3X1a6ixP7o zb5m~lMW78@3Z=z~=~((X#K*I#j)Jj*MsR9DiGrb}xh0NhHa4)(H8wH^H^hvMOmvNn zOkp7ajv_?jCzl0{byNy$HhBIuCABOyC%*u+dK6_O(8x%^Ej0-oVOEee1I3^Pk|p^H z;2`k#4F<K;AZz*+P!b)A`wdOO$JiQLT9|@PZ2(PqxtW>44?cn9Pz9LLO1YWE$x5JR zS6*rf=&%u}tHI7SG*<9W1_h>txs`%bX}W?&P<~QsQHg>}Vp(Qtv5taEuxAjcw)Oy> z^jVUxkdm5{T7tKw20COxK?Ah@Ut1vsbPhv_rY2<G3?!zh;O?&w;tx8z2H728$G`}1 z)sd5*4?d|E+)@CY5L;XVKH(=ZPXV;oB)0%OO$k}mg3~1MSvsHtFNz`SDnO&<pnX@M zxlT|wza$@2+m#l8PV$CN3xl0uXbwFY!@?32#-Jm1+|144VT^2}feCnzx}haVDL4#4 zftRA-o>-});25G70t&zI4Cpuqbjdg9<UUY;95gq8nXAA~fKRR3Dj0y$GP0d81z@@) zwYbCxbYcUf&7-fN0co9UL8fLk!3z(-p@5Q%z<ObXTV@6Lz$68bVW6QdP{Rab9_WA# zWV;Pak^CDBO~Ck587PEc$BckO$SXf1Paz~f7j#@JXltRTldpn*un)|3c<UYJJOmvK zT@z50k(5{j@^w*0K4|?V_z)D(Fi>$JcwIDTxCA^LgzR*LF`yyHGzExW1w=9dg|h<4 z6wur(iJ=A4rchjvnw$xmf<Q6A5EN{%KyU`H4F}B^l;kVq<d>%wf!8yjXh1ofB?WT$ zOJ-h4Q9fu30(fT?cpo7=cEMS^G&i*<zZ9jeNA+|`YHqPYPG)whf<m%_Eu=e$dWH;& zBcMlS8(LZ#S}B00m_R!lQb7Bi5<v|mg~X!tQcyVuD!4#ppALwTo0yHeh(KNAPz*h3 z8Pt?ffHY?l%TkL$n<l^uMiTRI&-Q^=mz0At7G&KHbglyAO2n83*!PCU(1O>}$Vve+ z(whfb?GIfclnCvjW#%bF8|s+Gg7&tQfSBg7D1iYs3q}~~C>Vhz@Qk6`vccy)SAaSt zAoqjHI_Q7`th&dU5FJ6I!bv&`3b~nikcGaE6$;=nRgn4M<Omz4L!ZTgIR-(Sz@3u{ z9q-8pZFL9D>S}@uP_!{0giaXC6q^a~L8M}wh8UPDxTGe74ihr5Qt(bqEl?;aN=(iM zwb)ZCauY$G%uTF_&xUwWp&%nOK3hRcAtgRr0bhR4S4acx<^e6D0~MHA;9cm@DFVpW zN`=%s)WRF)6EN)v*&73mVh#AZhZ4|=rlMSp3QbJ~*eC_=d;{A2n3<NDoR|k%d6bu& znv(<W?Se8LXhVEvUOLYBtpG2~cF{@$)5WE^8pL`Y=61+95-22Hz>6gn{QN^eHCJ(J zQD%N=F{tBQl7TzRfp@mScjZC?J`*}zg_6LHkfYEOdPo`abb4Y=T4H>DK?%s)@Fby- zlb?=a3^?3j1VRgBjt+FPdM;=?9q3Reg|tM_F$>@h1U?_Y`^(TNT&2X)bWpJa-|eZS z16t<@-|en|x*HSb7BKCor{I*8UzD7!pkZifiLI{yR;Hk!5Rh4x4_<%<Y6TaUBqn9% zfX>s0x&hq@(0%N<YxB%J1s6R9H$4USqRh0k%#sXH37Vqdt_M0ME<CXW)T`4-O)1vH z(yoO$Ny!gX!e@edKaP2cIhDnk#h@H#sD#_vfFke)%*?!W@Uk#a@7d6#BtyXkRPCiI zIOpeqNB5Gkw9H|)24t4xCgv#wr52}x`&gifV(`jyM0c!M!N?4C3n)x8nD)ufO9vSN zzMr53l#{?!ZAfZzMjpsFItm_%MLGH9Its4E#i<oKAWs>gBq~D_1;>ISP{Yy8N<j&9 zc#3XPr7o!Fp#&PHgB^falCR(y?62UAF9rBQ4_idNRsm)kG#^7Lu<KzOkUGL(aTFpq zGdtCxI6p@>7h=2~sHTG*+=y(N3#k8+pQhkn06qZ$wBiLGvTzgg67_uHM?mH!>gJ`E z=;asX<>;m7L(Xb~uFwjGo(_q0;RCW=FlikHXGaA~6JrBYT@wQ%*t8kcHVqR)Q%wbP zBV%1d3v*Mbc5?ehX!;-rvw<AzlMhO@$@vAKty=kM@PQ%NNlT!a6397AWuUnh(1|LE zuubQQB?_q(nI({mG9YKCgPq9*F&;vKcC|n%cUuJm$jN13p%Ty;Sq9czT(Gm#LEeTm zk!=+~hYv#X4tR7{0a*mr{zX!QDFhk2f@rhm0-a~30P!jO2q`Wu&~SB$0_eC#u&Yxm zN{SM}$JFH%r|N*F4@*G%(m_pbh!l9z8q^9;LY&kAYF?(MDA<DA0}6IX4hJ=Oia{%6 zK?x3inwEkhWXY^G7yOu~Olz)8=u)oS#EO&(h`&LD>18?!d7yo&)+j-gla^lqJ=_X< z0v%*5(Le_@=$@#fkOUf%gP4+BtfP=z3_8}O7<5Dn;_$81oRUNxg_LZtQYal<nhP4) z$}a*@71=rp;06N3p!CGt+(aFP^u*jGP`zJ}k*Nc!E+L%aOo*bQRFEx28TmTUHav(< zN-Q#jN@o=7C=`L*pirErqfne@2qKIik|jC{C5fdv3MHwz1t7Ax#1KM(j+96(E-{8G z%K#m&t^k$<$r$S>fTP+_N1;kbp(-h{$eJrTBN4LrD>bhqwI~{NY@U)Uhzai9>nSKe zi)B#S^(iidsi?>-fppRlDsqd{qs?NY4Gj!p6>PzY1e8c2r(uCuAY82knt?-IGyrN6 zfj6WZDAhvT4N?ih)k=<_#wcXVI%tRi)BsBYx8Bk~SEIltT|v|BkcB$fOh6sEf{&<z zCJ!-8!KNRYYAG`YbbJ_e5npjCsQ&`#x0mGSL)vyQuRx}7F`WSlHl)@H=x|eTI6#}i zO0~6+s01G$=wDg_iAd0qp1P3v10`!vCe=tP1x<u0q~(+rXDC3M^_t*Bpio|rSdtNK zXkcU#Yt2=hS(O@Jq5z@-5=$~bi---3Kn0M#K3eHWE*DbHxPg|sm4Hqo1y$~P5SOIo zmc)ZruYo)PPDn}$s>PrL0m9&WhhTI4h~$x<rl0`ng~a43K{bH_4Z3_2bbbrySP#{l z6v%-u;JO>cgEUNw5xPL}4c<Jds%vDVXOs%E6ka~58X9CGl!6i-x>86CD%dKh8XD*s zr6LrA)`FlbhE8OI6{p1H#pEeLqY)egMg|5*L7)ISS_?9xt)Nh$VF=!k0dkyzf`S|L z^eULoLBgP;C?E?!Ks=vd5D8iF0tyUJqbWtf5zR(pn%M~6atgIHDX|F6UK4bCLFFaL z!H_~%K_R6gTR{QV4oA~$YG4o#u5^$BOVunzLDkSq&oUKGS%TtH6+&9*8Kx?zB9rD| z5d?{82RWvrn_`L_p?KYhrqc{LfKcU(4AA7DsUMzYAPovoiqthUNCAbaf&z4Hgsp-q zNDPrk;hG?g3y>y5Lp@V)CV))-f_i|eU@<JZ%0N{lLIv0^aFv4)!=ek)B0;kYA_&SE zAp6n0Y>4b-MBxDHqJxirPz6V1KIp_O(77$3TdeXFRCO&=u-FcEB-ni*O<G{*qFQH+ z62b`UR6(T%xWS~401CmNv9mPLalxRAkib*##avvVkseTiT9Q~);#`@WlNyqlo2moq z_apI2@=GAXpu5pB6LTOO=YSxP?qHBs9R(=QH7`X6bS7?aDrgMM0NgB60PR*wbq)vu zmG!m;3VHbu5s)4o1zSS|4_x{s=jWAV=9Q-EDA*dINfm*Il|W4`g}i)_fna8CWoC+w zLLTTi9Hb_hR&HW}Uw(11jslpKoS&MOX3gar;29rWl2}p-8VCbXNILRL^Rj~raxzOm zXILjE<~V|mFGFVgCRXSufEQsx{FMh*;R-#?0wR`@npB$Zo1c;jH8`xuGX<<Hz$G(R zM*)TFn^*x=mFJS04!VmgB|q1(qy%D8o?}UgV?}B)f(PC(t)r0V2|5oH#&OTdPfE;z z@-j>ELQ;!MbQD0E19U)p2K>`pD@s6-1m!s;79sImD@q(oN<fE>D&*xS6+@i^4LT?A z0ZG<e#TofUB?=JV1_Xl+-~@#?#1)`ZF;Y`tty_g;P#OZ6U*cPk2}vhlA=kVVr~q84 zR+(dI1?cQjhzFemf}Hb9^Gd9_+&q0;6|~X{oCAVVLCHxAw6atOB;r|;=L2eE_@$OZ zH08M#x>l4x?*G$K$a5`pN-To#VDdSsxt`8C3VHr%VE4i#VMnNDJC;^}rh^f#%7$=3 z{Ts-|N>GzZGKx|YQ;NZ-K_jvi78bap;t4t4DYGh7j|-GO6>LE(JV6Z~JrLKL3!Ge$ zM8SM(E>OsWlPZ!FTnr+eUtEkPnO|IN%>|Be&~b}Ml5jC=E~G?*tN<J+;KXCim4}p+ zkkudwTXVrP39<@U#<Au?N#96HP{h%c`GQ9<lk>qxz3ZW<1m_Txgok7%inuiwa#}!E zg_K0Vir`5ERS{g+nhP~IA}d47rl9ZzWl>}$@LZb%>Xn1DzJe`kzE{vf%}k(N2P<zN zfq@<fm^$)GbKyA~*?J^lP-Nx$r$IA3x+17BG~po2I+m0KK=s0l2V{Au6_9cRo+crM z1(G^Yvdu3phKO5pfr=L-SrFHn3tn0x$-u=xdYl7-kffl6ejcdE^>jv-fQVRgq2_aB z6=($jG(SL!FJyI)904iithpdX03!23_#kmeaeyoX5rH0<53VK@Y!x&>V+5L@gaXcG z3fjoUH;9LlyFgRCD9IYK{sdN1g3N=JT$-RIg!#!Dh-3z?o<Lor{4@=SDoxP!ZLo|5 zYFpWYT3FUx&<Y*N+a>uW!KumCTu3!M7FjNk`{3~dJ1QSEx&rp50@B&{(AbX#m3FZp ze<Ec=2p68=KwQ+=K^&Wp=%<56ZqhWA0$goXQxv@O^2<S+1d5|oQ(|pZLH!vW1(01j z3Yj_z*?IZU<J_Y&W1&|R)Pmce;9?zAKOy-p55z}|Y9$+jrYMp4`8k=O9zJy73+!8v zF<D?`3Rwy^3MihnR>(p=^dGJsDR5At8039$mP7a&)b>O89K-_!e5QgeXxlj0A0ROp zPKG)V(x(Jpw-KGCprv3G3-JU@9q8f((1Zr)iUM2I5(tvaU<yGrPD2&66%2_t80I+z zeQ=WmR9KQ~7sv>-au?)47{=o(1#JZ*aLHLx5<r;)z{U`81on8*)<%s4)MN}<4G%d> zK3X*=B^HvL(_-?JV96Ppwjjl*g0?~yX!~7GW`z!P6B|@>vLP&?!vZGR5ZP`>@`oqJ zY)InG2HjGDlryarvI(YLXz>rqG~mDmwUVK&LQqser6IKgSOK&di!XWO3l&hH<bX0c za;Si+4+U+7Y#oJ61zm9d1GkzW#SJxs23|@L8#K^*73_1Qps^n0-UpRv$)NUkY7sbT zfKxNp<bqaIV^1(hg(LLNA5fnKe1}1Fb}U*EiCWZ=n-);oe~_dBveP*~CmNcEAgKcs zGmuIiTKQ{(&Qk@AEyog0IFJxR&RC%AhMv`Gxxh6gs6K+0*$^*+Ix?WyiTr}pJPlB1 zz`wLaM?oo330g;iN_nsv=nMm*s7!-~3P@H*0Xz(6U;v#J1i1i)!NcXS<L5y`hC0x- zC8$H#AmyM@LQq)(+R6(Vrq%(q4stScp{@aytl(q-aXd&5)D=qLTSY*p?&hQ_fII`5 zQBf^c&@j{lmt0V<LCpba1ogWelk$s7G(aq8e_!ADaQ`457aavdBvqi%d=1wK&yaXG zM^B&7AXlgywD3yK$uCaT00jZ$wjW4~1~kY3nqh$?TkvEHgbALBfiROn=byr6l0cyh z9S(&|_CSIes>a{XRY4y#@0pXCYt022Z-VJWp2)K1N&$~5!Q{XbEzn6WYc9|<3Y=3= z466G<b6wV4;Bg$d444OMZ$KoIi$UwIbp8EYt+|TxKx~LO=(tJ<3mhL@TwJi;GQ@kJ zNkDQ3yb=1q9oOL063~g^pt)?wxi^p{-o*-~;K7+P*n$Fuq)gbcAemL*1smXttw0Cq z7lRI>Ey*lSt5g8bW@(jz&JxoB4U`sSBx;o@*eW<8FZ3^k=tMY#To&}oCwLcC2Xujz zjsp0e9!+Z;vhd4wG_Apz7BZ#|NfMANq|nVnnGDpl<^s>)!J|}PU%@Ri4|4EvZem4d zZfP!bg-m{)LMe0>5F9Q(`N<F~k;(~BUIDFO^vMT}pMkG-iw7@M*FY`9v_XR%@SzV- zy^A#V0pg;R(#S1hNRET&Z6Ykg)Q#o~P(p>7qlNGqqz?k-gE~2o!8ga89LUmA4K=71 zBOL`W6Qo85bbSS=gmCc>b@Fl5Q2?=nLwz9(M6sc1%>~j8TV@AhgS11V5X6Pf<HGtV z(2y(!U5QOuNNPX|2#_6`SV9IAfgndaB^DKBrWT<Uci@Zbz{ehgMk`Z`i}Q;>OHh-O zOLI$eAe*^TKu3I*6lErrLa%BlQ%Ec-O047p4K+csKgbSHG7AIWNCug-C+<cvl+Gej zlLS%1!@8P~tIEJxCpr_Uy$=(C6g(i8KniD2p$bmNits)P!ccU_g0x|GFh~Z{>QJy% zKzA*uu?in*LTyih^kH)vWc`A^KCI#j2=erGgp>%;hOt%(s%ci>8VjP=FjfK7V+I)p z-bkWh1glEH@~F{`+;-Q2p4S8Je1R^JC@v`i52~U!en1s2c$`Z|K@D=3A;?DXEm8_F zH@f%-_!HwqNMeAHASZ)ac+(zO1vFb~fw#dxIwxQzw!sD1*a3X}LI*teiZZ|evKkco zieOV91t&-hT$!g96~%-0PUR<SD1qgn{Tk571V~YCL1ug+qDTM-b2Li4$Lc76HR?cy zQa}d>Xku{|$lrtu4Um=Si4l83geO7+$X$LIR$|XRpz&-}_bX^CWP+A2fIR`vN{~zg zx>G^}ECFrkfZ2E>0@88?jq_47D!>VYa9k*Wn#$nhs|QaJc;g4zwRDRigry|J5k~w{ zIo?3k6MUKmV~`G%F3HYApnyfHR<YzEZ1ILHh6pjF*v!l;L1Z)(=YuSyOI|~=mBOfm zM=!#wBt<YNa!^L?5anEOX|8i-QL+X&+~MUrG((eD*dPi(Jl@WXRnWFoK&r1HWqB>6 z%7Zu-G%OB2wGc5*otsz?T#{G>=?h02#wzF{W~NZ23_!!Sh7dzR-Urw2HjsH%1ziP0 zNC+S*dFt8-%Mq}M!*I4Ob}xa4C!-BwA+7_N0>Y?n)76Fe3K~?<3K86lhqSw)L%kqh zLv#i}<^vFhA}NM8EkV0UH6W_tp{@lFT8ISH7-*LS(h>(b56uOj_B7lAEy#Vb;LZX_ zEyz*es6Y$`BjNzrAn*yKpkeN$oWx>iCju6l@GgylE@~@FM?npoj#2BdScFqSPQb7Q z?qG<WP$z>qkdOxHg82xp*e5?3biXoK9IVy|q8L&)B3l9~2SD1O@d7G;kP1Ao0U*P4 z6x6_MuyPW*5^&eS`V$CKpaTtQ3L0QBJiQ8dkm@Kvy9i(%ni!D{O)sEnW(_1w;9v(k zx*XJqfP{E0m%ctHtX&A&1*8ySVx<6?0s$Lut7>SfXK0j@2JU7dc#!3!a6YJw3raLP zU`;xp&WjF238=jbVS)C!<rHKjDnPn$)?5%_(A_`~7HH}l%`v9bcMK?fL+k?$oq<L@ zAh|9*za(D)M8sPd7+7;bH<-b1Q!dEJ1g+(=1&4z*7kK?FXxJgOB+;4+wrB_BZ)>WK z%^|WL$lag;x6~AfdqIf`gt3g=85<Zts|Sz*cvl?60bwjUjNm#TnFFo|VLvRD;2N4U zqSeqGxa|nq+z1-S0uNn*JOL5_Wm#~7Q_zP-3s@~Eq`(W~5CMh7%O+qigEe50H8nK= zk5=j^z{hW*4Ptd5`!XSmj$vz$p+Sws5Hqk9AlIfPqYW*BM$~L62H+7j=Zw_k>;TZs z5J9QMpv6*PQHssBg`{Ie@SHd#BtZcS%H^PpV*n8Xc@CB`AjO6PXx<ofI3LI<ptAu> z3qYj<c=A*eJa7q;2u>|2EznTQEP-C?4KfFe5mT#ZBg)`09CR^o?4t=n3OaDaf=vVw zYT$8JG=*xAJdQ33$?0gKkTMh1P<YBfQ;RZwhbE^69@Iq_EY5?ja0j^+jMb8hF@&nn zwLwOA(M3T+!{}n*QEN0oXk85*(?W|^v^Y)8OTitb)JkulJmCvIKL>W8tO95+Ib`&f z3h5aw`9g{|aE^hmMO3g=0IfOH0G(J4u9`uEV%V^PLU4#<P>6zOh-;8zh^N0_Fjsj7 z=r}|TL)efYY*iw7Bnz|(-4AJ9A~+?1SFV8?%do|43bx<@$#Ae6pydj5$(@3&f-ZVv z8Cwf2tpI5e8}#gTNV5l&uFz%EK$9yPN}eHpKAygwA@P2$;YvCRN=2{<Baj|Yu%YV1 zm_337B}g#{rxhnB=A~(%=+RM7QU$F-)lmTDdC(d{sP{k`Kp12T%&T?^NTmx%64iW= z2sH8PWkOf%DS%g=fXqdB7Nib@p+@Iq=7M(CKrKNOUmztQjA;o-6uwj)st?n6u&Oi# z4YV8t5=O_cTm^S^T7FS7=vafyk_-jpNPwJpS&|PO*@p%l#4Tt62eJcFX@giGjLL&n zJt(n(WCTPpw5I|JDKu{&LM1gX1$#bG&{aUqMTjs$6-UcmAh&`rVzm&ArH!&c7-1ah z>LFwvE*&5rAy;7_`>G*5SP&D0K}wK~vV(W3K-mzqKuk-)j9`L9%I(l>3Njmpk<Ev1 zaf3-hq5#GNIR|?<fR@}Spt=scT2%qleIUb-Tx0}YGzJm|VUQj089qA&0|hlT&|+!u z`d9^3xc@Ut@<8546f+>bFpOk8nuqb4j?}G&7!R6S#mtOIrbByeFndu<w*_Z=(3CQ` zK!vFR(YQ^3t^CC(9YNZVB%y_)b3jnMtDg%-xd>7XatvGtMzIJ|fyh4~9tcAV5~Knh zBnrdu!V|VSnLxP-(g$({%v6lB6Qlss5g<{JHl%VCVj<ol5~K^eSs)oqv%s-~y-)^e z0AZve5$XWsG7%c~*o#99`;dw?kkK%Vn!iAzm?H2}65<FnlTg)T4>xEw!f=#=4LB4~ zlQ?D|;!dt02V;g(GU%pm(6z}5B}JL(>8YTrzCkB=fRB1pP)*T;Y;6GLU+BdkMtb0O zIEDjp`n6U;Uq3TV1G)ID1vv&H45}w=ZK35NXv75Pj3h`8SV3}PafyZ+%%|Y72#~m^ zUx<!^0hTFPG>wqzk7R8~9tIbe#2EmJWRMq;`Z|b6gGC2u9g39#{Qd*bc8H|ZB5>#< z1R>`J6)ULbr06O5=N5pruBfIcfCiC3C!v9_W(CVCfa3?$B|@qGVEbJ_2eg3q$sk1- z$d$101i2JCXbK8A5Qe!^PY;qDK+9;H1A@TW3ABj^k4Z+T2^OzO;FTMYy)!X+u%;tY zlLGESc;SQyN{|oG!Wrap5Qc8~0XL9wG#wx&!#ltlpuoeZ2|#9nFwU+eND_)cBRFXN zB&ZCC!q(jci9<2Ao+nfaL}BZLg2bU1Yi|@P2cod{OF<G)jIE0bl>$+?daEEgD8|=u zg(?A2*t)PFaVW;@%t9qV6lS*;Bnrjo9bBj|h{D>{1xY|LmQF8J21H@&{({7z7+OMr zhAN>V;APBMk|iSDf)qj%sB0c*b3drD2<bN}=z<zkAU-(hBATxtJ@BTTEliPXUJ9xb z<i?^l9%Z1Tbka1GoCAWaKnv?Y%ho~p0hY;8${oC=4Z<JT${1)y200#-SwU8SHrs)U z8>B)4HDt8Fn=j)*R|eQBfc7+_`cNygBo8W?S(1k;2eJcYHUqUF0yzUbtqq%)LMp>R za*$#OVI-pJ1{sVcN<o?kc2l5X09g<SBDEEujb3Ql0d+(neNc$iu+}wfB`0WX17s7q zOV1Gcz{MNPxPa6m&>2SH<684lD?mHSQwu<+4T09zVXUA7wGSXi+JiKp7zEY~9z@kq zDAj>X3F#=5LC)|)T5tz47jh62+BNkc&%rRL5Y;LL?JZSs)G7mC#S1PuwMrpHE6nvU z^@x>wpi6^M*Y1IJgAFW$9rFUwh6oXIS>OPG&X!PP;g&AglbWcjcwoy<VH*LlExtfo zS&Y2R5X(|KtdskY<s^9}3fZug_vlOSK_=l_!)L9K4PR=F$jmTjM`ve)7MUQbP_#AA z+6vj(NUON;s{@UQ=|S=dG-H9I0<t8^koHTWKm|S6Mw|qAlO~O#3e@C9nq9;dRIxe= zU{`>*oszH;6J$Jbizgsy1{4{PB}k+sL#*otaCrr`5(4ZW(851$1$erGt^I?P)8LXF zCI>CqA!4BEOsIgqz5*wxL;#;Ep`ZZG!JzqZ1r3E<aQS5jTJ;8wT^yx8NIzsQ9!Wcu z*T90xDfmPhh(m;>*b5J+M$mj0lnI?gh0of9VjU?_K~<5t^cCh-*mO0>G*ANqly5+C z7<0w}7SK84%#u7?)f6j8{Q;jH2G=Wa9;lZCs)uzzjdgI5sRObAVK~SN1qDaMqE!WO z%UQuzp{7Q`DO;hY1{|}PwFpEbxZVL@r3JcD2viwDoCCVBT^sBa2n#fs3SwzO&!z&M zDx_em06DJ{G93>&EeV?JP~|~99q@@xP-&POVfsOf_dyedxdkwvfs!J~r|?OBkb4nD zEi@rgqb9<;gcxKi2qW8vv`#=n7vx6NWd-{BWUeU&*#pAp%akBu$^}J<>A8uZ^Bh3S z{=u;dl0h$+5X+T7`?XOQ<|4umq!ZRC1Qjy2&^4~G5(Xp>!r)#SL;-ZY2S^lB{(xAZ zXac2A&`20`cmpJiY7sUMfmC5%><N+qVYtW8eMDg8F-R{iXTw7cQhm~GMKQ=t3gGD~ zyaPWVW%~M{;>j&DFEJ;xDpdoTVIVT#RlLZ{72y6spLSCSaSaZE#3@3J7Mz)xrU5?V zz}6OLuLL%T0a@r0V2M&_p>CnK1)Y%u333Bn(^y;8oHPY=jIxPd-$=_8tO?@6Xgxh` z6C$+f8lr2{)5dNcO0kJzwGPysu~3E~j9~<07{eGQu{s(kdi9MowM?P<u*kslVUf~? zTZ2s!ZZ$SZxO1>cVmMLP5SJ6dGT5C6mcr#kh$IdtLL_lG5h7`VycHI?;DDt-q+vMJ zVq-J~Vnpv~3M`36%?FS~MotRU(uWs^=%puukC^?0E`ihn?+SqQ$3TTLn2W9R0~_mr zug%A?MF3<7s1`-vu>leXm-mErZGaRK-YpPI?VTGSYq3@AxGQydg-*mS4v^`nr2(Ye zMrjMcx=P?UfbZr2X+@MX;0_U30a8s0=Hrbt#LD!6jW*<s0ibg!KzmK_MkTVtK@ADw zdbgl3qf%rd9DvmA1({DwbYf&08b&dwlZJm22*}lR$eP&V7+DMvqIhE-#XqD)J<gno zWG0nj6CT3|Uy&Whpt#8cAL<l<z9j$@b$IuJfD}-c;!%nsB0>kp77>s`paXj#CbXIX zcl9A-E=c_@0v<-v1nsYa#(Buy2Z6;kpfMG=CD4rp@KF_zdXNLb-9gl4FsNA{*^A(< z1~l0h0dfw8O>hrD?1g#(%t2J?Ae}H@!Zm=lG$?3821mf^kyhFuY8zw=L3szH9Vz}m zxe{sM32q6wdnMov7_dpO5hySRY&%kw2Z|Z61j>L4$g8N415G&KffeL|4#+48*aXz! z4v-Nb3<(5iN`?(LkvrRf&<FM+%(zg{wJZt+If;3x3Pt%P;FAtO^E9bBnYo#Hpe@^= zDHqUK6=+@$eseqOTnPC3mBgHqRM1Vg8L0}elM@s)Ad||PpiwZ8Ip7OxbP*Fn&~3%2 zrXgHPE(`2K@I61EHTw`ZKoTP;&On}l?P5U06kIuU01cuGWrz(FC&|SKBNg-&Ai5xC zgQSb|K++%^ut-AA$p9(Q0v)sqJ_sD734|fD>!55~Y^Z=LJs1)|acL4fQd1!Zf+}c$ z2kO9K4NFbXi)(O1Gx)S^P%=u)Qz$JcNG+mUO2|hHtU_W8Wn?uObl@aJ92{%;koYVH zo&FE<BeGx#=x}#Xv5=<#E$SeOA;|@_s4lq}Ri+>VbUF%H6cWi04G=cWBnS^8Q<4Ze zP^1`SK|w|)bm=54gvrek2z@9K77D(>OhKVSN1<E+ypBerAhjqXv7lHJG)D_sSepmB z7yx<&FYHE_Vw&XG5>Va&1s5n^K_dZtKbbBh)RBda6>JqC1!z$QR4Me(YS@7_V1J@F z!ys)NLK_&7njVM(qC~+~0ldZqrCS6N)hIDm&{8PTRM1j@F(EMt%GhvMl_+RKFEM~f zLP~dtbZ}`dcpePwX0$2|qC!VO4Z;B5fM5t&twvl=1fma=1He})1efMQ(-f#ML_Q7% z;a6%k<B$Rp6cz{zKs->;VFoBj2EJAZGE80qDiJ}!hb#^WM38C_hM5Cerv*C94x}2= zy+t2>2iXdXC9Dw!G7e=W64Vh2+VI=}-h+mc3?PvS(n@B~p*MXMY*06@DriGbX2v)D z0P-6wBv8W#IpjcLG?YRVo`-21Mxf9mm@?p*36#Ph97IS%QUQd7&%7cMJ()=ZI<|xG z{UFO#5dV(6w2$yNy;3M7y@5vAFl!vN+65FH5C_t>`RJRUmsyfu1a2&Vrkp`7{gn7@ z9k2l8epFC*q5`$S0QU$;iw5K-KXBa#YvzF0c!FlqAqreTSN-XL`~<?~8L35}s}Vq= zwh9_4@rF7IDe*=+3VM2aAXc^lWX&GjFwiX)2*V)P*nw{k)KO4?7?zh>4!#TrbjzSN zsBs>j4RRH#s}XG|a#>(M!aWaOBmm(-yOj`c!xsU7xv(pcU`i@LE3DE$_v3<^N?Oo1 z1ymMPr9)2YvjJV+0SO002?UX{1xX=FE!a7N@THKnO)*$|ocVd+1XGlmo&mm|7p40N z4mDV07MFrL4w#)0a1#;U(Il#S5dyjaw6r)CVs&b9X%58h;*!i<P|p`~-(&^a9h2n7 zJwhMYKPjN=t-#HHP<sX5h=tr<1?fkiNEBs&dMThN*9G0BTmm}Bpb8R+pev;mY!yH% z^r6>ZK_tMdmO%|a@Ex!kU@qtus-(msXnIKp-I;|@0kIvNc}o(ZN+5?eLSz)c=I16t zjE5ZI2o88u3D9|taM!?8Lu^Ob1>x%`RKeD#z+xB?P~@_}0Sq$^wEqXRyaRORWm#%b zdTL&BDr&xV%Pa!jDFN%;fRh8L+yVE85F1^fom<E;)CvlYpo_&&Yyw^O2pZ)8=>^}I zs89qtvjJ=jSUK{kkRT~kXOQb#gg&rqV25}@76fT2fC~{wgn?G6BO(CA(@`iW&V)uZ z>=X&u07xq6rZh;$6siJtZUtn_PC-inTnv>YmZC?YUw*j)G-DN~g0oREs1|^SaB^x< z323J^<P`bB(!{)y%o5PG;b0%YVy-wpHx*Q$lxJinXDF0s=H!5{E(M*prjVDKSfr2$ zzlaLDhAI(!@f;{u6&96fKs=<cpaBj71ue)mY_Ox*KqokWI-D?7;3G94;RKQbjWdEy z=YWWS%2kL$<Reu<l@UxWG;A>L(1z%Tc?o0=M5O_2)DV1iHOMxIxPra{gkfL}IyO(k z7jh@0f?H8$YD!LGUP@|_da*)oehTO+Oz?0Wq>u->1JNl4CjyAo;9fOI)=)toa&(I} zbU_<5KtQKgfRZdUl0moMfld|y9Vx4=06Ik%G@b!c01H8w252`D<~Pv2UupR{Ir-(F zF&>bO#R}=AiA5<2iRp=;g8~&mr(&e$rsh;C6oVrXyjcvCQ&6HEWF_RlUIp+q#-M|1 z^%N8|K<1Ygrxq#XCRQqBfUcDX?JP^os|2Y^%*j#6PeU;WlojCvmc<HSuRzQNoni$# z7FYq4C_xvg>p{X0*(a%KX{pI2pj+}%3rjQ05_6#Um4i$L1x8{HIO2*GN{i92@CA7Q zR34}16cp(wD1dJuvsEa9a+CAHR@*8V>Vt)#Nw)+RdD>uejiHeTN*JJV4u~jpgd7~D zP*LbU0DXN<w6kl_7Da+hHMCVVw9qp&%SnSCB?4Yp1Wx&27P!m+v%sY@m<37?U`7c- zH_BolP)r-@fOCfq*eD&aF*;x)bU@m5N<hod!I1;X0H6&FcHmu!C_87tdo~no6-*&s z2dOME25n#T_j85B4=BIERGA>DGQz0}8em|v3~{Q0hat!U5QeIUYEV#6(1f2}2{~m1 z6c#z)1KUA!Gf4h}B_T&pJ^)ucCHXn2MTvRIpu5RaOB9kS!SxF$Awy#xY#HeKNRV}) z#E##ysl_E=|AJB(rb=WFrxurh{S1l%OqGV9>#DF7FA5onpyPcri$NQ)p?4+cmzE$* z0EG|~!@R2i-mwHu2_Rp9ZA1?;kaIu@37&Ys%F(M1L~TYc3!Khi4hv3A1vxDfoRdL& zqCi<5ybMYKRK1jBWagn=K~1i;2z@9HfP@U_P;Uj$mL<^19^kOk1RwSUCgRNu3_y{g z;F6k?T9OJ*H7GYmBA52|_Vx-PPGMj>Kq)5=6y7FC3q?U^NI{G>0Uaa-vJ9jSl<90h zo1qZ#h({$ndxB2FBhGMD1w#Xn4+*OV#XC4-8|fJ+Xepp3c^r-c=>aEuLj$lT)YOkh z6F3JzHGz{QIOIT~f<qIefI%Gdi$f_wHz@WXi<)4GE&#MOP9aeNbjLI}HX(P=!;Y0f zZT2aFYQ;n)P)!3GM@X$GNG-|)WxK>2g@V$eg8bstVm&S{kbUtc1_oAO_k&_o5jOD; zYT+Vc6(j{Jl+fY=(Fp{32%H{m6(C0pfVL5%ozxFf1HvG~z-oy-Tp&$B1MDA!dqBp3 zFscJUA|Q<A*edwNl91h6AXV5fX!$<j)3J0QZ5{kZfm=)9%YtE@ZP3NS*`R%Bpo@&5 z4I^YnK!#S3Md0Io$bzK!8NU-r^DX4gNTS>gieXUMfF=7P`vgloA&wV=DMSqwj1a*L z4RAr6rh)Um1!G)?y1{G&&y^6ocLAmvy!a2x{R=R8RQE&AWB?_9q>zNDf#q~Wp-(Og zoSk9D1()O(fU2v+f`X#_f}+gC611)=s12N)p9ky5DkK+yt|!h+Q~+IiUIc2Xf(~MU z+;W_oTB4Ajr=S47rW?f?(5>RB$)zQkWvL1v{ormyu?}=B45C2+R3L#G*hn{t!<|{0 zo}OA<l9~cJAIJ)7hk`BWczYvAtKAs2lp{BI5c(h`pc!%r2q~%&3u6!o47}qSF{K8H zG<bqUQU?l5kh>wRNl-$7X@$`6jkX{uP+oxu+du<JO%1g5S-}QGqBLf~%0Xw#AUgsa z2_Qo-OKyadK=PmrX#;A0fr@6(-d-QjwUDS~D%A6^3+q7^!aWG$fUpKkkts9<LjnSP z@E79BN^Hk|A@?Uhj({D6=^Nmw3r{ix4xB)=k3ppunx(p6elX}TKIqMvu$CY=0Kh?q zS_vl=r6y)ubAiqb1vRB8J&_H3Y#eCse0~}t6HxcWH&A|Y%goCx&QQotO9Qw2VKa-E z6Y40pb3l><XhsTt;v^_oauw_p@({@YB%iCGs{q}?4pISHdIDSA0!jg3C6L4oVuE{V z3i=A*q304<h=bZ48lY7Q(5WW)DkZd;CYa-4^PixZL<KE~Vd!$;<Lkg-?2?+CnF48r zgJacJ!3fl2H-;Rn2WcyTdetDw0?^O_e8^1?lIJZ93>2(D#i9npcM70f2T~1c;uvWv zz!JGJ#&si*U<8%mq+d$}(F+Pg%(@SB`7>sH4XR#ziVKT$ATEL&;0ez2AX8u%p$gJX zhSb&gOoMc)A){CL)PW;c2ReKN&F~;wvAEw5>*Y!nnI#bSgXalAmp)XaRN%7_tPV7+ z1n%pD&ZgEgNYynmfQ_+Xw;gn`Gd@#ui_@dQaSGe#0x7lNr5hq<2(=$faJ3(ZYd3(R ziiG=`K-t}~xHvOCPa(gwq@c7!p)9c|GchSAwOApoC_fi6qpy&hUyuoE(xV(w0rsyo z7y8K*THrJSJ*xuDw&v0TH&<a|pv+>;r3H?As2G?HQU_*01;HICYc9w|+fXrZtU(V9 zhOCT1S@jEE=nvb{2tGTtq_ijxR01;$8IW39l<!)R7@D51uNM!h$n-L(?sfwM12Yp7 z1qK5H19LM|Fl}H2;TwQ}k(q&lp|P2%nYpo%nYpoofuV_si5Y`}0o7fC#lTX~;UWwM z2Bk@<SY#1G#U+VpX$UR`3*-?41BmB9G=_pfD!?kn&cMXL;G3AN;2*3I0V<I|7$nBP z$-uy1#K6E%$G`yQZy?SOjv*mIP?aDZ3m6y}1fYBv#mK<G02P-?&d=3LEGWoH)yqjN zE-5WeO-V^CNmULA1}T1SvNH}ucZY4|1<|9Jx*>p+|7n!_89@0SU;Z~THZnrb|3=0} zqxqk@F^%0ceJuq@yo1_dDnY4bnZ=p;c~%NWMwSXH3Mwv%C8<^lMg|6Ex&|h?hNcRJ z7FH$(Rt6Rdx(4P31_~O%i6uG;hNcRR1w~+GnhGjhTKZi2T8bb8W70BnQb7!l)Wnq3 zBJja>-~m6+V1ET?g|gHlkZqtjOwgWhJ&;c2%)I2B(v(yMrP7kj9K8%B1um|#{LB;u z$o_fIJ*Bz%DXBUNpo_IZw?To96oIqzbQGW)A}XR|;q1!jSXg@sDyvnLr~__%gUUL% zZmqmTm^y?QWIh{mvlqyAEzne55rhx&nt}q%O05*o)n6qF5Eah(pzBA$SDxw=mlTyI zmw-B~E{P?HAQ}|tI-v3P_!0#z$W36H))0?^q%@Gd2ek$6q&yuieJzl~6%@cBqoD;3 z8%+(6^B{o(W<gv-Fi0RK!AP))TA{^7;YHaBnmX_;tI&W0^)L`22Ue`0096hPJE+o9 zPz)%5CTSINQbB9QbD<uA%9o+b=b_4%6OaeTFtYh*`ioN`2I%WU?S~yk0JR@9M2_ZU z&{QOvP%?Nr5+(==R|N&=Xa-DBUmtYsr9x3^ZenI0sDp-R)`Eteplw~y5gm{*9|dr- zRZvhsv~XcYLCuFXb78_z7b9A`7!sgnE~wRtE&*@iqDw#~(XnX(w|cQjke6qmkqYt| zBx9gt9Y|O}B#?6qR2R(SDLRmA4iyxzXC<g|(6K_;%ehfe>>+?u|3ljUpxc7<lCdi$ zQ<PBq-xO4@z}x?33I>Lz#)gKY^*@=xO`0|$+W(BwkoG^LFL6dA+W%l3PZ$^&GSPH0 zF)%QI#03}_@VEaN7#O}VFfc?iFqk9y3Aw2yi7AOCiB{RZE<TA#sX6f(*=E^B<=Ljj zxy7lO1?kyol?7QjC1pjaxeN>pTQ}_n_aSx^>{kJ~<I}8@n$BvKGG;+eyCZg=<$K!n z>D1%gQ+{@adBJ~=-8dM%lRrw+ZNrRPxemV`Eit#)!M>M2j;CBmt55#qrs~qYyb&R{ z9ovrx-J3m2yxqkk-~QQ}dV~AlCOiijKEyCm{s*-?Xps8}wf_yxOi|kZ;QViBFq;4A zl9Keb6q1s`J8<=qL6s<S7r@vMXBWWS%D@y~7XV}wVrq&K7RV&<{#j600yO6aI(`?_ zV{mfz30BZ>$}i1J(S@`e5;OBsQxtqs6N^g}f(uI%i&BfBhsQbR7gR#lPHQ-8g8L~7 zuyun0ddN!$brf7uK^B147l15r&d)6<ElDi`xgt0@6SOu~M<FyX6WnttsRSu;D#|PY z&0sj^=al9qWhUw<I49;MrX=bqIOgOifNd=XX)j7GPAw`+P0>?u)y+-J%&}6i$t_58 zNG{eZO-j~FPP79z4nZoxKFb7+iKeD16z8XvlqVLYS}RoMmntMD<|!1VreqeEKyQf7 zECDT_)z2@2EP1R{$SeUFQ3_fI37$|XNiE6+Eg=MR-2Flod{T=+iv-<M^HPfva})wf zlX5bX6?`(2Q}aN3oxyG`00|anq^7`@W4RTjrYZzOouc3d3Uu(KsI@|BW=TeB5xgsB zq-O{Ul#&c^w-0Kn4ro3@Be4YJg(8Lg0?@hmnhKzmiJ(ib;hHf50O8LRg-pl__>BAl z(0cU55{1kX_>$Ms;?%U#936$E(h`Mm&kzs)&=61{IQm5@ggXWWIr@b}S}T-imSlhq zJWef3g&38YTac3py4@wQs3<WH5}CfPLCzkIej$!do<5!-kswp@ixk{EL;PHWgB9HT zgA^PU0vv-vJe@;*9D@`BLW2VQgI)C$6hP~!K$A3>Aq+ADEs#O;NxAt&sR}8nC5f3i zklmsnb&>g{3dI@ur8y~(1)N2x$*GxTsVNGeK4SqmxnZ{i8jT<`pkc0%2<|U}e60XV zP}ZOcqP+YP9mvH4pk-blqfjCiq#Y5rItre7$$B~priKb`MTvRYIhlD1!6iBhZkcH% z847MW`T0dU3QqaOCHZ+e3cijC21bU42D*mE28JMWLW3Pa6eU?7p%-Ofz^1q)B{N?y z!;T9+Rsa&p$xH%^rKF~1=A|n5dirT3>Lh6@XlQ68YT9TdX=>VQBx+iL7+lIQMUD|j zitIpg2t{0|qZlCHAPS=7{5;SK?P3LI-SVPD&}MD$3T{x4I{7$)3Z}$jaJB+3#CFU{ zPfaRH1Q`)rnp9AfpI(%hTdb*2lwVqsnU`9uP?C{Y0$!s48vX=jI#879DJX<zq~@iT zr4}g^<QErbCgr4pyKyBMsg<yFl9Z}Ylv<FJ2)d^zsZt?1zo;m+xBztfL|(cA*eR%% zfEEUW+>w-;ng`B`xtUd|DX`>_o0yyd3caLMP(K#r7|0?_PspH53aW`#;ALI9up?d* zD+($>M#BX_hr*%=q~wE3C%6L8VIe3Aijxy_K#`4zS|v#3l%WKRju`No<><`3Sn!aA zAD4mxnh^NN2uxw<*fyp_W?pgxvZzjeX-TXCDD$HkoSBy#33451*n<n~uJ{y?r!_!( zCyGnJ-FiRp;_2cN*q{*DF=%315#VS9yB|z|7Mwt|gWLiix6+D)X$1A2LAFCKF9Y+y ztII)C+J0aoY-|+_K<jXeQX!L2kad+{+d<R726_gX3NSe?h$P4^kes0cXu>!zITFm# zRDjJNB3uR9eeI{9s$c@P6l5Q$2t%F{&qbRGS5Sxq?F-h1UeKwar4WI%As7_r3JTzn zK(HYo-3r<Y#tJqHexSpSwQUtl5bglk7a5%iqQG|^Lp%jG5iACoz6UYEwt}WvG1O@* z7$Tj24O3@?MV%2Ab;elK8N=0qreA9nK+~`ApaaKH1!xbxn_IAJh=w0%EG{_$KIsgW zuSA!Rge^Eg3L5B=15mJNYh#2-CAz~Z;I0CNM`i_x)V5UsMKy9TWmY02B4H9>e{j_j zpV5fSQQ+*Ppg?Sn0+kxD90jh!K!Jsxt;o+ppqMC8$SX-K&Mt;zC%7e<I++zZnU$c6 zZXx4RnK+{ml<`1;ssOq(MIp1o)<U;8c)VVXL9xrwLjc3_kQgR|BLJH0ci>a|Zb* z6KmvyA_Z!4B-G?eRFf;Qm>dZ<nG5w8JWwf_lardGP@Iuil$xTES)rqlS*eMp3KR<H zDj?Y(oJBzdBy=i5GKx|YQ*<&bAq=o@QKbCS(uz|{Y$5hQ6v2eRA&PmLFnSq+p2qd{ zVe1z>^NKT5QWe0ig<ZCX$V*VS*=9l+5NowTVXl=4b|`4b7V2<Ym=6%DA`z-0qhZpq zpbfDR(J(W?*$R|F6u7u*_4Pp)ZbD8+#uA|AiJ2ud$VRXl4_C#c02(5Vft2wI3NHC2 z3I#>^DWG|W{4|9KP&Yv#QjZH%e?dl7VKrDvehDnQfl?-+oQ9|sKmiP^pddyn;Ht5p z(nX*^HP8d+6_8z^cmYKajEy6^!KAU~87{(wWs!n{wk@avs)$w40#!_v;OGSBwhE9G z$R{9ofJG{yBH(fn6y;nB(3(@B2(-8Z+AKtC8(?XN;4dDz6ck{Q6;htB3)(XU>N!P# zXTi820S1dAP&)}0N03aHSE7I=qLA7lATMDSbx>nL{!~x^HMUYg>o4^TVC|9O;zIDT z{f3Y@g4qQs2S9NJQwFJ5Y(Z-)p=}92&^8ML&<XG$i@_XNdjq6O0a87J$~He}D+A&N zc+i5kN=8H*fYvk-5v7n+2=NYhXF4dW#=@H?Ad4!%CxnCAJ&+O&Vj+sgL{NeQ+gyRD zdO_+y`XRw%qmWpETJ3`5k-`ad?n!YW=%^Hk27RywEd>oEE-Y<<w1O~1%2pw<0$B#F z4FOUJ!XUe}Z51>UD?keqlM{1N!IcUU7sU{0TtPRfD=1{5q;SaUP*}MNc89HMnnH1L zA(SdA(I_r1)U;IvuTBLk&?zo1)B&%E1j#@G3R=v7<>5;liwj|^8r{O;74q^+K$~1s z6zuJ>Bxgek)3dFCrUDlzVj*b&>T8fkq74l|SAiE77lMy8ht!{tlnf4TNVSt!qL5{4 zV4Y=SXkcKS1!`Iq7Z*ln#o8KJbAq}xpfaZ<GsV_GC$9ut^%X-50?VZ-Xizu7>+9pF zy$gym%MwdcHA*s5;11ErtbqC*T;wY#=xcE)XQrj3rYZRQ2Eal>p(GP@?^S+oL40~@ zNj$_8@p+}W$OpW`{H9<FI^`d%Ft0Qhs<;?gCFuNih#AFph6V<j3gE?mpnZ$Vsd*`x zkgcWQ*<vnq&!pvp#?QdP4v7X(nFDI(Lt6Wwum?pXD6NB9QlJ6^Q6qz6v?MbH+|UJQ zaxE|kO7pdl#m>-*m@6&62s{Oj8n0ZOu#})}3yETIDFI8sppDQl1;nRbBQjDiG|o`c zD>(l^5-c>{Ku!cFU?{%`eC|SUVG&pr$k&iC%meqNaTLn1DiJf0SA)#YinRq5@Q?}s zoaXfmtPvK0GJ&3fbuFHJK#NkJP!`Cn0JUEA^{XKX43XeL>5UU#Y6mF*r!EBr1;QyF zSvBrd4^jn9`Cuj_5rT3Ns9Q^*2IB-3%eJTq9i?Id)l1N14owH38i^`3S~NH_;jGpm z(x7&lp`HPxZi5KHYBUHBwU$E?1Eo+{Sc7Ot3J2Rse0>Ko54F+*i=owg5HVycLG3k= zwczRx!~r+nKu4E=vJl7_wvdV$tQD!|0`oOBweZS<dWQP?wfg!Bkm%-uR%{B8%mb}& zKy4@NWf8JEZCi*Ykh`+L?NL~*3=xMI2Carcr4*7dxWfl;I)STZWLc70so>ERP-7I- zW6X`t%!3Snp^S(@hT1^s71VtI4S&JL{6NvG0ZF>BatWhh3bp|;s1*V0Gk~gCkeQHP zxB_CyQ>KnWW(ByEMjEKHu~k4G!U8QO2jwF4F%;Ms3n;&U42O23iS3|+(hfMsfeCP( zg|zVly@#p*>r_C8xezH4(n3ZVc>&c{T>ARxO(Rff!rJ+u&@>!&!HHfzf)X0)&;+Dl z*9W%(Ajt^Yl?MkXiU_3JZVO5uAanIGhZSIzAFfsgC#+A8f4~3|w~&F1SOqPV7zVYX z^&tfTVk7{ZbZWWiGHpvWOOWROb5nDJQVUB{i%aOd{>RAF1Zn**c>dqSz+iO!57i<W zk3stS;33J})LhW+Sa95f1suyt-HVHy^NUg)3krf#3%H;Por_WvK^t3>DiuQ0^A(&@ zlan(O^D;pjX$=ka4b1h83=AzGJJ%4C?uS+?fP_(WAWx5jszu1$ILI2LxgR8FWhf1? zoP{UQ2ayzx{9jN&MK=;!|7T=s2+#lKhT!~fZakX*sTc#eje=%t<g&j2l-U&&21N+~ zn%IZT_2c%!s0;-mfSUhdbpUnu020do#-^t5{14gxXKG?%GFtyr5UoUOMdW{Y+z*2K zKP@jMHBA9g`^RU%m+YVjBAN<_f`SV&Dx;vUg<^n$mi}l10y9}4<$t~S;`|)Y$tj7M ziNTq<)awKg%KxbQe?j%XnUVQu{f`-0v=AX;{r^Dj|DCjU7kKUdYv=i(Jp;4|fe~#c zQvRn=?kBMR-^9e&!~l8!KREvzn2qlLrAxZh*HQp4YK5*z1sxb%240Vv3ObNAu_UuB zv$!NPS)sT9e5gElIdNhh7wkl!vQ&lK)RK(+6a~<zWmaiA=v?shqQsQU)Vz{nO+5vd z%Dlwf%w&b+#A47<U7nD0CNokMk`+pd67!04z{|)%3m-sBXY-3P(?QozgQieG(x4SA z=|zdTTo88^r6*=4>Vc;def8Y+6nqj(N)q#`GIbOj^%TNVlan(t6HD@S6rA)FoJv6h z6Gf>xIhhI?M#c)hiIob5mX>CkTxe>8^b~yai;^-^z)C>_z95IV<rjhNw={sSYzKLr zOCbf~pTrzc<08MPQXw%1bnygeMZ1EAk)eWbVo`DiXorERCKtL@UZr`d3WjDnAZZIO zE`>1Y_Gi$Vc^w6})FcH9kes0rLMj7v?nzOl6_<i8+#yDKh7i>X779iNhDHjy3XUl$ zsVNF6sY#{jpnU+TsLBm=6uc7i6pYMKl{;soCTADqgGS-i6oOJg=U|i|Yc$j|f@(B@ zYDAVb)iY4g1qZ8<fuS+v{1%iEA<${xjyXxGMJ4%&xZwgd!$3=>V7t6+Ksy=o(!ndY zk;GCUoj$A!yb;POi}gz?3sQ?wb*E$&rRJ5OisdGjWT1#Bfp$CTWhf!FAVIsaQPkMv z7G$CbC_%TRBhR)YoS2_m09Fl|4u>~beH|m>o&EiSLxL0x4GavpxFEyXpv~d&8HvRi z;3;dj{4mI39cO132qPe~A~grRrz8&|5R#dj>X}!PT2z*pqiGE>r6@5k1!SBCh)~E) z1g&BLGhq^jP?^j;=!SWS8c>{rlw{_WfUU<6HG~L*w1Lzj<kK>9a^k@!SSFW1%+`XO zQVlg<t02EPJ{P19><%z5u>vNUSDKrYS_E1_qOYY83_9Bkl=DH`reQf9ls+IfX6Aw2 zkXV$StfP>ekyxalrIlEeUIv>j0;vM0cwg{w0Odu+`8nX}0`M|y*u7vNRhcQE!+k*0 z0Xhl=MX8{z(ugDNAk*;*#YLVjAXPdF1*t_Pu(_u^(4y>u(h`@<BL4!=`CtY*(4&ix zMKbdsN_<kG2aSPU3lohtG%zxWRj^f1QbN*<B3fPq+T7%l37X@FsfBn2Y*KkaVo3%> z14Ohqvnn;dL;*wvB$i}=JY!&F0ChB23&^~@#N5>2{G5QI{DR_WLsJ9r9HRmxDADD? zla06(f$uvF0<S}W8U$K$0y)f~xFo*_v{e99XoA({rj`_CCMyJht_@BF-*^aK6oO{2 zV@U~`fjEpTDakAWod!X`Jn+@7XeR1wVLB14t`xkxi-3us+bk1vP>sZ9B19dUf5DT7 z;0%zNsiTmUrK6CY4T(CiAfz(&OaUKi?3n_}1EBDO2!pm_B!TvQ<&>qSAQ_ZWnrjW3 zVp7o8ho74TQk$8VS(2HUlUW7Y7nQ02%GUY0u#*SV!MnUb7tkc8r)QStl_V<UBto@k z=A?oWyFzAOW);|gD$r>KMTvPv8lbuha<T>n+_rQdR&>+vS3z6v<U3pu^fB?gBdw ziO|;vl}MSnrEu4voFoXUILlL0Kvg|>ZyMMp&~cN{J1D@GKyxSf)CnvH)Pn;Ma!CSM zJ64B6%}5N%&%xzT(9&kmuAAii++0w-1v;2mM<Kr~wWugFCAAoAGid*movi_A{TKL5 z3$TUIvmMZa23+WX4&cLXA5s{BA`@&7NHyx=eqjHDO)AMFY!1Rn=%-JD&4GmhXqBlB z^h7-c@YxWs^YC;a=jWk^D5eL&=IQGzfXbEBBG9cA@bp_*T#}j#N|UJRS6^QNxoAKH z7UZmEaF)me)dpa1>g&T2Z+;r+M!6#JjzrLQr=k)C=qYSqS3)WikmZTRB}Mtrf(Kzb zIAx_KCTA$*CxNzJf?Jx9=qt|1M;HdV$XQ1r4_r7vPk6&)11N!j&wv4!BcM~L5oKLT zVs>htLSnH(X<l|-etBLoY~NxrBy9526jBRI!7hP#3lzaxxrqhf015yH0CMsGv-R~A zGV@YWK_}!x?^pqM)lw9&`x_iVAaiqy!9H@!Nle#KC`RVwl_JUHCc-(8G76+O4|E5l zr!%C|%=1qJD}ijY1&JXkM3M6ecJu+s>nK1CKoUS#2s0dFlTWZCOaMh;a4?E_5H7T; z10^h21%Zfn$gVWVYLYyc)O64m$CUhB#}aS_jtF9ugqD(;UX+>&-Y5$?)-NSL7m<7t zVRj@|WI|#MoMe-oU3`Ka9i5{BKozhF!eB_r>Fn&HkORK2sW>&SI1_xBaAHwvqJpEd z0_aW+1#r_F99gjBSW@CxkqWxT$UsLS&#|N=AhF1?BC{AhEh3x)>Z#>}E`0&FY9L3W zq^9T~WuUzLJYBGDa8D%Xr>3Q4g7z|(6obqE{G?(%1vLe@=Mb&|c?@*T3OE%a2$X<> zn~R75M93j$Jdl2UeFbnr0_Pm03I(Yk0OzdW)RNEwWN#<ur@&enpfi_C3qaW(RA+*f zLyQCM5Qc7cwo*_ADR9dVE7pN9ot<4^%mPr$S|J&<T{{mZR+5>U3TiikTi1{{h6V%J zz2J<A;%y{*iS#(Mp@2{g@if#LkZb_5kMq+M(sS~YP>L5w;RQ~7dHG4jC@BsUyhLLZ zuOLMd#ODwTAer4KKQCQJArHy{9rguf`<9|e`Ih=5mLMF2VgY!0SW#kTUP&=HX@KGl zPtgUoUJIfLWQS*pjslFESc1fZI001vqyQX@piSMC#o%4v;O0d-sD%&C-yrKDrb7-4 zD9$e}N=}7%9a>Mqtjo_!4@b5f!GYL~!cQy-2L*sW=z^l6L}a_mQ$ghbrsX9lmZnye zK!O=;4AF53R;aJ90I>v=>_HyPE6vGKC@x4$PKE3V0S7-?-2?S(QeqMH>`h860-YoP z?gPLBxdhE(umpUAY)OeL%;#>2$)G}7*Fet{6qI1EVJGzU!Lf=`m_aK?<Pxcb$na3e zEiEnq6{NYPIVG8pa{-bn6%rNF5|cr#XI(>mBS`Mk*H;LGpIQq!NFLmJ1Rr1v3VHY9 zqF``kACzBS4A%qhx#uP3K-=Cq(DVjQ>(E9Gs1<=!uR_ZI#9Vm81SGGckOwL$5_7=4 z7Zj<G{1R}&FUc=S%t5LF;4Kl@*cP~{0ckDiC^$kZ6VPUVQ2hbw8iDSFNKt^;gH%X^ zR_PR^CW9)n9PmDGP=TqC2QJVE#1=*zf}#(HJHa&~BwR}KvO#rOUUqOnPG$+b7=i>6 zL<u+n=qO}@E?w7wmYDHS9;mOMm!DRYUtSECLJ`Y@R028*c_1|*`9Z0PDM*IrgLgC{ z;sL^kR0xpBfQW!X3K}0_MGzsFCUA`8r=_J9Bb9vw!yMu)r1An@V=F*TBLs(0X&&e( z<<t~NO9#|wE6Fd(O$8+wP?HKY083=Fz+(e62b>AIAt5(47d*I`m!eRTnp==xlvq>= zPr9HMKB(Uh>2N}oLQV_-b?TBq3&g-K1V>R=k!K1x$pyG%=K6wnTw!TbV5AUK0eyWO z27(%gMEVlNM4Sc&r6!j_(f}w#A+ZVJgME|dpHy4{>Z|A|fU02sBIpKFkm5Yhs7gRl zezJnC0`z_|kZ@v33N$`oO;E63P^D5UN<gN9y@N$MDX|DsI?q4NH7B*A#6Jn#W`wvB zWGq<1DX|De0$SQ@C6<)<1tT?}i;5B}6%vcm!Hp<*nge%A(@OJ_K_lB>2f_4%`!yk; zhL(<kR#{kTa*2+D7Wh_e9R)4;J=!`7S|}&pLoI|E0?`<sSXvPe$|?}2W03@9wg9MJ zM8yg{d;``Z1iMH9a?p(im;+{Og74{6NXksfOia(u0}YXYJ6;MJP}hPfs493VsR8$b zCZrq$mFcjH89^6%6lFp#E7L&nALP;ja1sH<fEFa5f{!{RA$fv&dWoQO6QDi>9Sj1h zz;jA-^N@;kkdwd#UnaO2uK?*>`X-hXWmZII#)6{@><Vxz6<oPPLKs;P$6yF(L;_y^ z<SC%{pTP|{kg?$80y;kkR1zXag^+Ck4RM3dKSc`x&;V8{xLSpJ6Bdy<sd?!opt~R- z)`F~oHcb>#3&E!Y!5R%($X?b_&?+cOb<WRA0i{N8kqd79!Rvll9|$ST;0YaK5O{Yq zwEY0_J@{5mM4AB|s)AAXm8XN!XOT0gM+NEw!V@ZZWjZPWjucRb6_npVSI2?RkAeBT zI6tQpl+!>*!-B-%tqD**1Z#z5jtX#Dik`i|f}mj5*9T3NLCgXTRKOA`<UWmJaP)za z4_E`F5r9<1quEpf%Gxj!z?WJ$mcSeNMB4;yVc@g|9ERu~0t=GjA+QE;qQq$tsGd&D zLAMDa3QjffSil!@5cSBGfJ04RA2Qku?$xJ42d&&ZeOwi^(h6Y1@H)sG@R&QANKUF# zCUg=3rq|aKqQ)0Yc|v&JAz+?!KoBHj!xV#~H3%#R8e#`Cz##(>1Gyc{N(1FQXmTyd z%mvRTfG0+ZqYXiuXG`)+;)_$0K^%w$#ZXxT&`btMhX&}TKIj<?(6k8>hBTtwGILUk zp~ma$`v!O_fDc^C1SN4up9fS<<P{X<C+jGHE@RVC0L@n9piH2EWK)Za^NZp^a?zkG zDL`{+0YU!GuED|nLGgZ$zOK+o4X6vibC{rsG987~yc7@v?g#}J_@QYj3XtL<H?aWX z802ERzz<wX=qP|j<^1xCiy{7pE6GiSs&Gn8%P&d=T>?@7QU>ATQtX&kl3D~;3+6$T zf^re$aOjeJQ0C7q&C3KepdcMr&?F@|b%BBl6uiy>K{^T`2Kd4w@C_<pq0Evz=YSy4 zATp>Ng4{&_u>hnqvm_6!9+b$zofYswQP_vNGr=SJ;K6PKu+^Ym0p{7&5W_*PPb~rs zv4T1mxrqf}9pJD6o#hX0vgktZ4+V>-fi9EACIQm`uC9teH+*B&h9M2|U~y_8)JUiv zkRWKn9+VJ4Ap&tONHi}WZUXoi3dlh(pdm77>r4kcItR`)pw<|K3(7bUUU?D7%%n`v zf!0U{fV;HdPB!=ewP;XEh0OZKMjOR~0$u^^b1S539MoKd)lmrj)(VikW~ES+Uk(~R z1}OuFE6Djp`Q@H@AQymKgX}BMl2lNjAvq~8-#H)%RT+GU0W=r`k^+s>7Q(yVAQ6O_ z@NoeY#ZIu%0#wD|oR^uG?pRXdoSy?X5u6XP3FnpO`lq>8lt9$$fCu{h%TkMS5(_{E zgSveX1)z9^@|+-zV2BIB)11&y%gZbQhdL-+{1S6hQA6L<3|dG)Q!-?IfP$75s94F# zEH3f&gcu2x2MwJBgGWx_ENAHK9kiH%i#wK-fCdO4+CkBiSXz=FREm@~(sJ?>OF(Ny zKq)9O2jn-1YJ`LnL;$26wmI1reEF=FR$!<nXgvqyD(ifOL<K{IltcwczJ#a;oniz! zm;jtWP+J_3E)ytYf+x~J+ZYWYyY4}A>Y&4kkk0G^Z@mNekU$$Ji%W`<a|<*;)9ulj zu{sJ$x}dr72<QBiR3%N&`5j1?n1VDF=cJ|<Xdo^;1n<68PyiL#o_U!i8fqXLbre8U z8MMv-$vNle=Ej3&u{FRve_!ADaQ`457aavPaNU5e6m$w9rczM-fuzzswIm+3>d-*t zf=o}$P0dNogX#jOT~KAAU~6EluMc*1IH-_?oqqrxwkB$p6%^XwCUbx*I7Tv4N<n9* z>1u%2N@yZ%(gs(1pp_7y@B@W8D2PBoYY6E|phgJDk042;a7QQrnE=~699o>1o@%84 zY6K#d@+w5@f)Zw|LbPsfYA!S-f|qT?DkwzjLRLN~M8iZBbo25-SqVf#3rpR+(p->G z1t=&L5FK6J0PxI1ib8aLUQK>lTC9RDDBwT^Pey)eQ89#@1G=400V)8gs-VT7e;TOV z0(Z-b!PW%?Dd<9~pv)3%Y7`W7LFe{EE>=`f&;`%<x?~nX=BQILixhMrQ<fkx2n!?# z3L*vYL<p#q2QwfgJeUaz5e41y^vq<4xv{Ydx{x&)pmM$(bcZC!5MA&Z6Oc1ObF2yq zy71x@Hu$OwFEe2xpu!te&cx)!<S9YZ8^|%Bt?3{dl1ac#!OW^uSb_t|q*i2>;J#c7 zzVZc8qCi{+K9mQfA5=boaxElbLk{6lfKH==#39q3NcAjq7!pGqv3v&Jn1Tp_N-0ox z(bENV!!D?60Xl>dlm$RNjN;7P(wxMS{36I0C@fjnD!911IfnX##D{qLy22Z<AZc(L zMFCZTkEgF^2(*9%w{ei<JwyE9`e98RL~wxS`@y~gZN~=(NScBMa=~T@F4#aB1Eowu z<SSU7Ld#6xyrh5}nULT>v@<}qfu<Wk!Hg=3)Fy$})F8D;Z4zkv1u6=zzmbHHd}#^^ z6p%vnZYb<pYml72erif4Xv3x(<VtLi7(9_eD|RFc^!3ptk)7#Uh+O-_;?c=52-4E= z4-ZB-3T{p~C<LHqet~RPPyhuvq>@Ck8I)|`^^_6LdJ1F$B8EUbP}zwbt&sW(Ue2M! zEl52GqnZE`fvZ=r1+Df-gVufEvm}wSEl4Q{!;%J4d8(SGq=TsF(exm)JAwr>1G#8` zR-7n-L4KtTDcCVW0M+-{5--S$NC`NxBp+9RAiRS;9-#FD%ncxeLF0Ik#Yp+^<#_pd z`uS;)GlW1&Kp4Y3a9rppDCMW6!Hpx*ERcDik^lTW(2+>6m2x0a3|qj30;K+f*#fS~ zL5e{bdk)5B45a$RY7lCshueX}B&6yW!!*?RL{!e;l$?ntC4=ljC<h;~0e1(;uON(& zhYxClgbBqvs62NL2qNHCPyq?8pAt**2{{$68g%9+hC`t?g6>>REiM6>iYSbTaV@x! zLTC5FYCM?FkX;P-ASjkF3phwKijMAuSV&gzf_tI_oC;P0sw$Af0F=@|7-taBJJOIU zU~F*)aw`aDra@a83eematD~d~I=!@*P$+;E*&<~IZ9~wBh#*5@7<?ubsNbhx13Cl` za*{2m4+v90D7Awc&;;B8?dYbI=H`M9-NaJ?fGh<?4@9XQ=#U<G$_2@RFtjNKRziIA zLdRqXxD=|2w3GwV1aAKmVK`VF>BfWl6hxQ~QbwBLpl%8QgV7p<NT~^2hoZGjK(U9S z1A9e)qQq7Ksp$r7w18q7G=T+O4X==jSSk<c0)P~NEW=WmLG=*uS24871nczaC@85G zD}h$9rk6!$V)Yx;V94ry>~6;HBuL-UC9{Y~H^J2tb`)GGK3D1ME4YD9;s^T`9+nC& znb7_e?!W|h4KZ8|QV*5^ZI^(gICwtA9s=P0B!)StjSa9Gh-n}TKo}`CU^h1}AJly& zU~pbOXkdUuli_`K0*1rV5k$R9W)a~yLmu`;Nk$+qgD`f#!bb=QxCpKe-X&Ae*H5h| zNzF@1El~h5ia?8ppyQpH@WUTLHY+IPxfa4lT#@?6t`Q+vI%Xg(aO*&wGa?FiWc9WR zpt}U%X$NE+YMKCvKr^b6YfzAXkd;D!tF3AZ@^}g44j6^>OweU4peD6KUOr^(1$0#m zsCb6*Y;ElnRC7}G6daTCi%K%{(qr;K-K@&Y6dh2oK-$;gXeAoR1)vc{upW#7L(rL} zAQi|M*I)}w4Wdd#u&~ECyx&V8#^LJ7jd9|;;vi4Jts^qVk=0WW<8WiZSB>Q7Q5fTJ z<LDpbka!2hIXp9fVh%D`3kqSR{+tn{kpof;cQHQ2;LHS4jW*1S$XD?ERFRqtncN3$ zj({K6pb!ijY=iF-RV@ac$)%d2kXw)mX?n)wp$%jy=_rJ`2I(jukF|q*0&)ptQ~=>S zkT}c{umNM$oKyuR9r)Hcq)Z4h0ovcjVFYwsKp`JxR5UfG7<_LO$Tl#BTM1VW>ik23 z7o-4W5u%5xXsck1!#<SpYt<BxyW#rK91bt)u^WXvG^|<-G6-Icpc$kHD%e1y=C}-k z3^Sk(C8jB8z&jZj{ajdZAdQhj`~uU0<^o8k3Xd@m1t?>g5C?!p@D&k5v5=uwT>gM| z4dG644hTYX2&hDNEGfZd08|<yBoKMZRslLM0*ZAIMg#?15xO@(rh;4V_^bshz_1vk z71T7xrxPTPp%L6%gKQ4Pr5C0|LA6)`lzd=(v>-!nCE_v)t_EZl^7c|Rv%t+XT!w%p zF+2ikfZ@^uX~SV?f;TX6=>sc3)20FG!P+6sZJ|amxKFGAPF)bCXuiWyAR`-sG*tsF zwcwhNs}fLgf}_MnF%7N;)HVUdAzT32G*}Xa%q*#<DCsC5ccRdIp$Huo#}Ra@#o(3? zcuE#LRj8|gGBN;iI^0j7$_8|)6Wm!K0ffPbdIi~6;00b*3dk$?6Z3LX6hO1x7+VR7 z!MBy=mX?$z=Hyf=q*f&7lon@}p*GZzd<e3L_$C>?<`|?R2AK!)GQ6+`c^BHTgk>nu zRd=BIH<!#J^hs;%App||UJVE-)sr&wKr@M;ow49at;F0^Jq1^IEevj9rl#njPVRvm zM{UnS5|e_462dA-NT5ynLl-uur<Np_r)Yq;j_bg8ibEp=6mW_#&-xc270aLyEU46g z$>}J74S;HcI6*@Rw8S~JxEPcpi%RprH=gI`DL@k_s0jnwW}lyoSi1$)4{|BmJq2iI zzJqc)xG{u?ALu#Hc_l>MXP^(e<6Qx=?FGEsT}uJ9J~}<MBsH&0L&+~9KG-(^w9vrY zH7Hm~(^_BOUO`F8O36?Oxm}@AtYB*kUgHLK5GYDHi)~R9!B%TPri?N*iZwy&d;&u~ zwX{IZFz~7kh2)G>(3We^(ImNvC5Z|}nI-u}d6^2C;5{0tMfnOTnc$0!is46zC@R9O z)Y3-`o#^YsEiBH@%U4J&DJccbuV%tkgLYkkg0NTttRN>*AvZHop|~_91$2x{W`15O z^2rq-FM%-3R9o0p5vVsnDCp}$7NTV4<|d|R=H-LE1k+?^Yp9@6oT^};ke8pQkd|4R zSCyHcm#C--J%$bLHu$KeEojgZE(~!1Xf)FnW+WmO;0X@geFU{<LCX)o=?YZg!FReq z7Eys#wiPSbs)F`Ef<wU;a#a+z6p6S?1Eoem<S680r9p;)?{oq=7MzG7M|^;|pu!Qn zSO~fl2sC1$XP}@3iXC{L9K5Yb3#q>f@nUj*E@*+D9=zBF_013*R7F@ULKi~S05AJN zrXo1dIebtN0L$g@5&)6wK+>RaLtAqK@-Zw@z{kgc)+&RIQ2?!~0<Gz;1jUS=o*t-H z1j~R*Ux>><x<LjjY9wc*WP<MMfSj8FEu0C}PoAK$JS2Nk@>7e!m&~MAWEPj8j1WKz z9FT<|OzpB5;(X+y5o8O<YXriqxHK75EFx7GkQ4_CD4$f&(y`)_qMTIF=_k<OfrK7x z&<a$efmW0t))XTRf}*z!aA^WBIMGp1axX3dGvg8CsK`cuvnj}5@P;OZX$4{qQY5Mt zE9mLz;c2?U5(`8pC^13OB%##eUs_U7T7qN~YH|S;CIPMrswpVx2C^8L#;FGso@AsG za9n^&A2?P3t*rx}+yU8%1qmYXGIUS^0c$`{0FVXZkh5H1qn@Bt02T*tVhe_DMbJyi z1oh1!o7q8$P64#%3zXqYGEz|vbO38ZYyrWr5`NYTiiOZ^0btD-cEVQEqgV;mfppdi zRxg5kbU~P21dC(04z!91!;4_`kR1hJUATP+>IuTnib3`yL;|cE-HX_K2vLsgKd=X3 zO`zfu$Zi;0@H!bSO@(Ceb~_E&LL5I&&?!@%elD&NuEE-d3XpbRei}$Q=*AFmAqCo$ z10FS1uvGv_C}?ToGX|R(NJkSW*n;ka1sSZb9~|Ns6rvF1>geL>=MGPWuwn}86a0!4 zK$~ZwM;7U&Btot@Ldh?nW<I>l4=Do>wHEer87c}pV+kpDBQ|D$MroYDYr50&3sUnm zK#2jAhhVPPQBW#}4KF~7Y^bTAqnV&4g4_u!$l=8#C}<!`VNyt{(Mkb?M?gklbO#aA zAVVRC1$jc(vw%ck7&N^LS_Y?wybS;*nN*SwUWANQGC3b~nh&T61JMd4v8shE(p0bo z9cG8LMhs*R$n~%RDe(0x;J63Lz%X1hOc|t#gGqyq`@!i0@JTT+H=^o;u3%KKRX|!D z2Qm~Y0bkmPE)C8QMLvn3&F5&IfgX1NI*0(|Bs2>l8o`Gj;FHbIOUELOem04bv4M$& zC7KP6@IyhMTS`Ix0b#`MxM=XE9Hdz(G-*T7o*gsjpfpGhgpsrxf#eM>&CF1(Mp9u6 zQelK<0`$Bb1zQC)jZg`AXroCZ9ZLg>MpR3Yj;X<v%tIVogDHu0j18tF#tAmCJt?4| z0AXzFBthcPV{E_+Nl{&@uaA&JPcxu`9CCOHO40}I7zX7S6L7|Yw!}fUfG{+Tg0@pC z*eXC$xfbleBS=`HIsjS>CxRB3qn&dD(g#U5s9Hcd6HTd&f(fJ;1-Su+p+<uap8>fA zC7}{B5r=6Yb6{y1;yl>tHYh;^-XoL;I=BTCi3-{ZNU0EZf*s725VfF_T@*k!T*Ioz zXw;j&q4!GVAswg)8V*1*7xl((n0n9(GVrMlWr;ax8W2~1L!1KHKd%RIs~%))pdQG> zV7F;F=O(6WDrhT!y`_~070fFIi-CArsE*S}NzExqj882|1gS9ALei&|hw3a17i6Vi zqp=%SMS^KywJ5OyT4o78Vl*u$F}+x!xID82bgWh$c%UplEe(7YM`A%iQGP*DCg=#* z?94pyv3B6YArK8GNN_2@j@p8zb>y6@r2zH>D726=yA~wu6cDn=<%E`k5nM(~0W~bO z6_AS?h)QFSYH$*RnWv?I8m_2m99o`%TpN-Psv_V{L@`7guQNbSB-LVYb_F*>10bCq zlt=*uCWh0nl|<0fLO=-;Tri;*Jm5$I$wE2-kg^681E8(>AR6KXggDd`kON>C<W$5O zYDHTGw9$Oj#tTRnNVSuKtwM2TZdz$hPElg62Ds3J9ISw}lo~Wa2?~4onOJCNqCgu| zATwbYHbxNy9i9YD#DUgkgU+;2O;d1p(t#APpj8Q=LfKX|Cj~sb4t5k&65<dv(;<yN zbbDZpF<S*ybEru$AvFCkmw_5-whF3-7J7!JIpC{yLCelT2fM<|2GKCppjI22YLE~P zvmwnmxcXGE&me+0bU@l;NUnzn;7|=}p21CrxE&;fLp3;3k&FiOajAu*K#=MTNQ6LZ zMf~a^DbrR#6;%^N7?)N^)6FNb#8yGo6dGx;#$I9x0bTid=~%So=cVJ<2W}{0Y6J@t z)QQzj$T?KF^rBSUpiqVR6GZ}-ZfJE4(gzP%NUH*u4!8WWVvut1{5nz%YY+=soQFe~ z28u#WuzqloMHNRalVLdnTohx~f-*aXoS9H62&`I-(3jl8Z9}PjvFbI(sTWd;f;7QG z6C#2mSfE8aBoSlkf{5eLi&W=<bV9Nck{}LkNR=u=8<HRnZAi^>gf=8W9NLhoeS|h7 zK^)ppoAL;qsN%RZgHGb{bVkwz5x}J!T+@M6!=el<fJ?Q15-9Z>8o+W{eo`@-QcyLC zHhcj}njnl>L#9EK9mX()j)D@bda+f2Rb4O<G#f!i<1+|a5#g?b2pIsXh(NA@R0JR% zi7tTDOb8<&d=d?TR9GNGAc-BqC(#g4Ee0|I;uR2&L<7Ke8^{ERBfwlzjeu8yup|c& zAkP>`DM4J#NGPHam7}eK0b&*!qz#7gB{Z0Ja5YB0esEn$i31=tCV3{HRGUcgj3Q2Q zOhM{Y<Vb>ukZKU9H)5**ne>G8MZs;HXan>r2^3xUqsrL@RFXkbF;X>*QKu3#3Axve z&21P}EkP5}t6&UAV${F{jfB+0ND%-LAT|6Ux-haFvM`B8B30Q4*C7d#XdF^ijxY{M zkVNB<s(6HPNP;99hg9_=j6)J6(Kyuh06guX3X^Ikq_u!B48kYX6mTN~;m15MpHxF2 zjSbYM2FCb6T5?W)ajFJJ3j)nDM6VXXLRpK8+BiWNr(mmqbHbzuHemwFe;^EM{3s&y zq7D?I+5l1xZT%>L*QF_xXMpZ208P%oRvMwt(V+PWWCZaO{~*=)R-J+5k#@F#xFGMO z6(=X=r6Gkc)~1;nyltkSh_R5BkjFvGT0pa|Ff$ZDEj|Ts2MH!b2cLsH48yR9fmsh~ zA4Ah2ObE?IprFFh>;)N$uP%a_h^TF0BCx|#Kqi1N$P#Svf!e}V193GehzF2<P#mN| z;sC@&^DW3R)J}OIGhrCyQSg>Z9J?(cQ+yy5*!#>NC!>wufP~O|0kVb6I0KmmiZ4hz z8pI<uu0Y)fgibXOmy);w=|_qy5EsptpfIInT*2}R$ZE7O2MM9MhJr8$nT7~C5Rcd} zhxE4)detBTl!QCP1f-CM2%!0vUSSWh93J|3#zQFxf4C*ko-~9{Y#czktDrc5G-uTy z0+hr7!~{?rq(Dk4hyb1A02HFINq(}{0>Cm5#Pvv34MYIVJ0R=GEVLlzA))}nCpH2> zg9RYHkRneF#HA$iK>9&Z2d!j4Tr{83EAxP?hG!j!??6ImuAv~@L8c)>4#Xoi%)!Ge zAg$0m1Lji_>R<yv!4AzaU_P2p=@sr^yOEMRn2+Wb3PK%h93t$%T%yArG9rcOz^K7y zX((t`L5)xVP2xbxE2s#XpXnC<a8H`!9f+eO4&YW`*nrZJ16hHsVG9i)^Z^H0Y(T^* z$`23+LJY!;8Ho76#t*~|h@^-TCTLCrg(I1j1B$V@Z6hw)z@u`Y)n<tNrv@7xO)Q}( z!r(?Dmtt^1wD6!?R)RYKbL!IvW2zNTEMaz)L5gAfKT*dMK%N6(e0@tqpyM14Mi~VG znFqtfnhTqrLD+>B3y2XHkkMcd!NUu)#e^9IkTW5CKo=i@mh^%bMZwqfB5Z{(<OL~! ztp*0!2*Z#w=fKMp6*3iUknVg!J1Q2Y0Yqau2P6ve1hxW8H3vK~4C-JMmw+;WXG(Nt zEVcv>G6jUOn-7wKwF@DmL$E;-q`-()O^HRy1(`aK9bpJ-Q9H*VGhvvt4k1hzq2VK# zI@Ab<iGsomygL?jJ`47w3{nd7HkwCmLF-PyTW*N-CdfK?S*W0<rl5#F8-eV`m*k;Q zi|njSY|{>yo(H)EM`8gFa-pOaM0y4#N}Ndtd$NIr9quH9FkaU%7BS9->??#4hzqc% zBGOY3F{uZ8;1NhQFkfT$gsx#MIPHLg8oLr){scuFDM^Sx@*%<nDAg+{MZz5n+T*4H zJ+us8;RjJNV8ve=D2pNzbU3X_zi?RL2kk#17k*$%v8P&4kdmHqLAr=Zy&!d%DHtRQ zN=XD#F-RFkN(Ot=7P^QId=?3j9tBxQO40?{jz9T=V-}GdK@p1?#+bebIRty*2kB}f zrxo;)2TNxQ<W926zVK*->7b%dK{W@ObddanP=c#S0NGD^0wN~yU=KP1i3Ur8LHGe& z@*%IkB*~|sh$AHh5lB6#g&%TkU<+y@C!%0}1+Tb(wL{@O4bWmmEJ+A6`M^REwc127 z9I2IsB#PF|B|T{nN*1U|0_I927hvgafIN+wFHs^AwcUjo6d=X;+e!H18O3QhR=`ly z-$03IB-_xU0yW^keuDNmK>L*J2ru1+=9K)rbnyN&@ZAQ8eS}CBlile6IYd_hbn>;f zHfp4R(h+9FfJ8wa!Csc4^g6(<29?iP5<kco5XNo+NCuY7P%{H^fWWF==oliRMuJ<6 zngBtj!Z7J&CrBrui~>>v!l>~M5&>aQun{OnLCRnrNB1hY^$2R#5baTrg`^anAlva} zE7YzBo>0d0KgcOKk_@;+hE=~1Ly;0Tq*TU{g0QC^SODTlIY<^jD`99NLJ4#vRS;)j zPfw($C1TPM_An%neqdh5<qdFE4BI$?OA#)=g5r>r<U}ATf#aQ!8*p_*K=(z124NuG z4E#kRL=7oj5$YC-;1(-V0tfdCaHMEZ7Q~*aK{BxD#g($b&2&&B0otTQDJj6#Vo$*! zvq?|IAYH_yWRN<{)C>{@r6>X^8l(*7ZA4-LdlW~11e7#DwGMW#f~+JZ5rgc<pOC@P zi|jOthhtECBw+tw6h%1F5B9VJ3qaiI2FZMAfe1}P$R0ydgsY4I1sCZliI`M`nSwx3 zNg(yWJdVQ`;NlQV&jfprV<sq&3rI;!1QHTjiHPW&K+7ZaVLsA&C(!lW=-m^rFt(9l z%%lVhP1IxrO%-5sKxGfKCPfxTYZjB9NC+hm)WiXEC$bYTyC`4>qqz(vLQ$K;n85*3 zOmQCt><XGpia<?<#W!+bp!ph0Izm=W{M-oGN<2Lkuspe46|iPdxr20>9w;TjFlGdS zWI&OGqu~i^OGB$=u-P=4BY~NXW0nLajkVSQ`2d7TFH%9e2;~}(8W2X!Js=Sf28A4f z;uWL}mf0XhEX+5mDUi`_P#D8oAuvgtUIkf6N_h&hAAgw&?vSE74Xf>#K>%_Kj)Vg) zr_oXlN`?WS7)rGo8WwEGRzNFhXjzNuL1cBH{DNL>fI<y~Nl#S7Bq;15NgyF%PejNb z0aw+iJr``@g3G_4*d!%o5lB_w6hJuCar9om4#zi<0#*PoCrR$VfVG1{f=VSNxP^<H z-oaf79O)aBvalD$AQ@Ohqc$OsLK57v2Q?$0?N8Lg18gy7I}Btp2$P<oLAr=Z)gX14 zDH|jTN?8O_H%J-G<LF++-iZOnARf<xEF~p5gIs_=NrU4U#c>pulPKL7sE?4dG$@5q zabg*Z4bV~&nv_s{hv^XP$%^zOMND$SOiG{_C6J7;CLv^hfXhhC?hKZIfdoCKk3p^= zC0!9nQ|QGcyhj6e5;jL*X^LX2gb}_*8HtBYxj=TFQm0b`>U$v;D4<x3){F*aGSZR@ zp`?PEOknYk;s&h!n!zyn0*M1!^=we09VI}}A_X-FLFpSsHA#IN@ZdCP)Dg6@3uDX? z;$e8L4N^nGm?K0tC`(YO(gwGD5tTOB?Vw>XT2$K*!*O?TAo5r%6i}uCVbU@VNCyZL z%0M7BAdH#{Kq4RvN(}_cT#zzYzJu2v5bxmX;y`3^dKP3UDMc*E1$c{DbI4jhG}mFZ zA2S$0uEAEo!bT0y6A)_Vp?W_D5_Tw-K<jYyo(>k3pv*HA`#M;>0<Ot1dOKJY;_@>n zUP(!1cvBd3%PCq4Ly0ArJ8<`SKx3+)vJ=vqAyj%oR1IYL32qRhB!6&woJPebzHSdF z<Ul1iW^)ZxHh}ODD?GuT#o6(}?_E+8HYj-TCvI>=Bd2X}JYxnnDTOC`*9Yt;EExtz zYQo-shSftj`p%ekK#NZF?hmFySndS{7CI(9Z4px`V-HLMl`$*;P$LT^SiuD+)-Dk7 zz9uz^5lCLBogm_zL2Ne&<v1MVO)e-B6m^79OacweKx<;u({0gO-JnE7TEZceXiyUj zD2hNghhf}w2C^8{W#D}lDAf`y8KJ5}-T{c>XEd*YtcKUDs8d8B%kd=!3=5$ZE2=p0 zn*$+-7a=xDsew)tcC1J(rYORphY_OeLW9_Z77`%u4qPO|oN23ob`mQ*dZ8*n5ewh; zht(sLL@B}&Ogm6g9mo=FEp70b!|-!%)R4}AGQc`GhFLejJd9c|fX!6^T^$83fKbiF ztlj7lk>K;0FtZGb(=f9u_@-<4k<$jT3c01lB??KY3JM0GD{KuFl2VfsONl}i) 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�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 IK=Tj)07}SHN&o-= literal 15466 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 diff --git a/cblas.h b/cblas.h index c8233b4..2c28276 100644 --- a/cblas.h +++ b/cblas.h @@ -50,7 +50,7 @@ cblas_daxpy(const int N, const double alpha, const double *X, void cblas_dcopy(const long int N, const double *X, const int incX, - double *Y, const int incY); + double *Y, const int incY, int ntasks=0); double @@ -58,7 +58,7 @@ cblas_ddot(const int N, const double *X, const int incX, const double *Y, const int incY); double -cblas_dnrm2(const long int N, const double *X, const int incX); +cblas_dnrm2(const long int N, const double *X, const int incX, int ntasks=0); void cblas_dscal(const long int N, const double alpha, double *X, const int incX); diff --git a/lsqr.c b/lsqr.c index 346591d..d1c6de0 100644 --- a/lsqr.c +++ b/lsqr.c @@ -32,10 +32,10 @@ Parallelized for ESA Gaia Mission. U. becciani A. Vecchiato 2013 // #include "cblas.h" //#endif -#define ZERO 0.0 -#define ONE 1.0 +#define ZERO 0.0 +#define ONE 1.0 void aprod(int mode, long int m, long int n, double x[], double y[], - double *ra,long int *matrixIndex, int *instrCol,int *instrConstrIlung, struct comData comlsqr,time_t *ompSec); + double *ra, long int *matrixIndex, int *instrCol, int *instrConstrIlung, struct comData comlsqr, time_t *ompSec); // --------------------------------------------------------------------- // d2norm returns sqrt( a**2 + b**2 ) with precautions // to avoid overflow. @@ -43,1328 +43,1476 @@ void aprod(int mode, long int m, long int n, double x[], double y[], // 21 Mar 1990: First version. // --------------------------------------------------------------------- static double -d2norm( const double a, const double b ) +d2norm(const double a, const double b) { double scale; const double zero = 0.0; - scale = fabs( a ) + fabs( b ); + scale = fabs(a) + fabs(b); if (scale == zero) return zero; else - return scale * sqrt( (a/scale)*(a/scale) + (b/scale)*(b/scale) ); + return scale * sqrt((a / scale) * (a / scale) + (b / scale) * (b / scale)); } static void -dload( const long int n, const double alpha, double x[] ) -{ +dload(const long int n, const double alpha, double x[]) +{ long int i; -#pragma omp for - for (i = 0; i < n; i++) x[i] = alpha; +/// FV_ EDIT + ///#pragma omp for + for (i = 0; i < n; i++) + x[i] = alpha; return; } // --------------------------------------------------------------------- // LSQR // --------------------------------------------------------------------- -void lsqr( - long int m, - long int n, -// void (*aprod)(int mode, int m, int n, double x[], double y[], -// void *UsrWrk), - double damp, -// void *UsrWrk, - double *knownTerms, // len = m reported as u - double *vVect, // len = n reported as v - double *wVect, // len = n reported as w - double *xSolution, // len = n reported as x - double *standardError, // len at least n. May be NULL. reported as se - double atol, - double btol, - double conlim, - int itnlim, - // The remaining variables are output only. - int *istop_out, - int *itn_out, - double *anorm_out, - double *acond_out, - double *rnorm_out, - double *arnorm_out, - double *xnorm_out, - double *systemMatrix, // reported as a - long int *matrixIndex, // reported as janew - int *instrCol, - int *instrConstrIlung, - double *preCondVect, - struct comData comlsqr) -{ -// ------------------------------------------------------------------ -// -// LSQR finds a solution x to the following problems: -// -// 1. Unsymmetric equations -- solve A*x = b -// -// 2. Linear least squares -- solve A*x = b -// in the least-squares sense -// -// 3. Damped least squares -- solve ( A )*x = ( b ) -// ( damp*I ) ( 0 ) -// in the least-squares sense -// -// where A is a matrix with m rows and n columns, b is an -// m-vector, and damp is a scalar. (All quantities are real.) -// The matrix A is intended to be large and sparse. It is accessed -// by means of subroutine calls of the form -// -// aprod ( mode, m, n, x, y, UsrWrk ) -// -// which must perform the following functions: -// -// If mode = 1, compute y = y + A*x. -// If mode = 2, compute x = x + A(transpose)*y. -// -// The vectors x and y are input parameters in both cases. -// If mode = 1, y should be altered without changing x. -// If mode = 2, x should be altered without changing y. -// The parameter UsrWrk may be used for workspace as described -// below. -// -// The rhs vector b is input via u, and subsequently overwritten. -// -// -// Note: LSQR uses an iterative method to approximate the solution. -// The number of iterations required to reach a certain accuracy -// depends strongly on the scaling of the problem. Poor scaling of -// the rows or columns of A should therefore be avoided where -// possible. -// -// For example, in problem 1 the solution is unaltered by -// row-scaling. If a row of A is very small or large compared to -// the other rows of A, the corresponding row of ( A b ) should be -// scaled up or down. -// -// In problems 1 and 2, the solution x is easily recovered -// following column-scaling. Unless better information is known, -// the nonzero columns of A should be scaled so that they all have -// the same Euclidean norm (e.g., 1.0). -// -// In problem 3, there is no freedom to re-scale if damp is -// nonzero. However, the value of damp should be assigned only -// after attention has been paid to the scaling of A. -// -// The parameter damp is intended to help regularize -// ill-conditioned systems, by preventing the true solution from -// being very large. Another aid to regularization is provided by -// the parameter acond, which may be used to terminate iterations -// before the computed solution becomes very large. -// -// Note that x is not an input parameter. -// If some initial estimate x0 is known and if damp = 0, -// one could proceed as follows: -// -// 1. Compute a residual vector r0 = b - A*x0. -// 2. Use LSQR to solve the system A*dx = r0. -// 3. Add the correction dx to obtain a final solution x = x0 + dx. -// -// This requires that x0 be available before and after the call -// to LSQR. To judge the benefits, suppose LSQR takes k1 iterations -// to solve A*x = b and k2 iterations to solve A*dx = r0. -// If x0 is "good", norm(r0) will be smaller than norm(b). -// If the same stopping tolerances atol and btol are used for each -// system, k1 and k2 will be similar, but the final solution x0 + dx -// should be more accurate. The only way to reduce the total work -// is to use a larger stopping tolerance for the second system. -// If some value btol is suitable for A*x = b, the larger value -// btol*norm(b)/norm(r0) should be suitable for A*dx = r0. -// -// Preconditioning is another way to reduce the number of iterations. -// If it is possible to solve a related system M*x = b efficiently, -// where M approximates A in some helpful way -// (e.g. M - A has low rank or its elements are small relative to -// those of A), LSQR may converge more rapidly on the system -// A*M(inverse)*z = b, -// after which x can be recovered by solving M*x = z. -// -// NOTE: If A is symmetric, LSQR should not be used! -// Alternatives are the symmetric conjugate-gradient method (cg) -// and/or SYMMLQ. -// SYMMLQ is an implementation of symmetric cg that applies to -// any symmetric A and will converge more rapidly than LSQR. -// If A is positive definite, there are other implementations of -// symmetric cg that require slightly less work per iteration -// than SYMMLQ (but will take the same number of iterations). -// -// -// Notation -// -------- -// -// The following quantities are used in discussing the subroutine -// parameters: -// -// Abar = ( A ), bbar = ( b ) -// ( damp*I ) ( 0 ) -// -// r = b - A*x, rbar = bbar - Abar*x -// -// rnorm = sqrt( norm(r)**2 + damp**2 * norm(x)**2 ) -// = norm( rbar ) -// -// relpr = the relative precision of floating-point arithmetic -// on the machine being used. On most machines, -// relpr is about 1.0e-7 and 1.0d-16 in single and double -// precision respectively. -// -// LSQR minimizes the function rnorm with respect to x. -// -// -// Parameters -// ---------- -// -// m input m, the number of rows in A. -// -// n input n, the number of columns in A. -// -// aprod external See above. -// -// damp input The damping parameter for problem 3 above. -// (damp should be 0.0 for problems 1 and 2.) -// If the system A*x = b is incompatible, values -// of damp in the range 0 to sqrt(relpr)*norm(A) -// will probably have a negligible effect. -// Larger values of damp will tend to decrease -// the norm of x and reduce the number of -// iterations required by LSQR. -// -// The work per iteration and the storage needed -// by LSQR are the same for all values of damp. -// -// rw workspace Transit pointer to user's workspace. -// Note: LSQR does not explicitly use this -// parameter, but passes it to subroutine aprod for -// possible use as workspace. -// -// u(m) input The rhs vector b. Beware that u is -// over-written by LSQR. -// -// v(n) workspace -// -// w(n) workspace -// -// x(n) output Returns the computed solution x. -// -// se(*) output If m .gt. n or damp .gt. 0, the system is -// (maybe) overdetermined and the standard errors may be -// useful. (See the first LSQR reference.) -// Otherwise (m .le. n and damp = 0) they do not -// mean much. Some time and storage can be saved -// by setting se = NULL. In that case, se will -// not be touched. -// -// If se is not NULL, then the dimension of se must -// be n or more. se(1:n) then returns standard error -// estimates for the components of x. -// For each i, se(i) is set to the value -// rnorm * sqrt( sigma(i,i) / t ), -// where sigma(i,i) is an estimate of the i-th -// diagonal of the inverse of Abar(transpose)*Abar -// and t = 1 if m .le. n, -// t = m - n if m .gt. n and damp = 0, -// t = m if damp .ne. 0. -// -// atol input An estimate of the relative error in the data -// defining the matrix A. For example, -// if A is accurate to about 6 digits, set -// atol = 1.0e-6 . -// -// btol input An estimate of the relative error in the data -// defining the rhs vector b. For example, -// if b is accurate to about 6 digits, set -// btol = 1.0e-6 . -// -// conlim input An upper limit on cond(Abar), the apparent -// condition number of the matrix Abar. -// Iterations will be terminated if a computed -// estimate of cond(Abar) exceeds conlim. -// This is intended to prevent certain small or -// zero singular values of A or Abar from -// coming into effect and causing unwanted growth -// in the computed solution. -// -// conlim and damp may be used separately or -// together to regularize ill-conditioned systems. -// -// Normally, conlim should be in the range -// 1000 to 1/relpr. -// Suggested value: -// conlim = 1/(100*relpr) for compatible systems, -// conlim = 1/(10*sqrt(relpr)) for least squares. -// -// Note: If the user is not concerned about the parameters -// atol, btol and conlim, any or all of them may be set -// to zero. The effect will be the same as the values -// relpr, relpr and 1/relpr respectively. -// -// itnlim input An upper limit on the number of iterations. -// Suggested value: -// itnlim = n/2 for well-conditioned systems -// with clustered singular values, -// itnlim = 4*n otherwise. -// -// nout input File number for printed output. If positive, -// a summary will be printed on file nout. -// -// istop output An integer giving the reason for termination: -// -// 0 x = 0 is the exact solution. -// No iterations were performed. -// -// 1 The equations A*x = b are probably -// compatible. Norm(A*x - b) is sufficiently -// small, given the values of atol and btol. -// -// 2 damp is zero. The system A*x = b is probably -// not compatible. A least-squares solution has -// been obtained that is sufficiently accurate, -// given the value of atol. -// -// 3 damp is nonzero. A damped least-squares -// solution has been obtained that is sufficiently -// accurate, given the value of atol. -// -// 4 An estimate of cond(Abar) has exceeded -// conlim. The system A*x = b appears to be -// ill-conditioned. Otherwise, there could be an -// error in subroutine aprod. -// -// 5 The iteration limit itnlim was reached. -// -// itn output The number of iterations performed. -// -// anorm output An estimate of the Frobenius norm of Abar. -// This is the square-root of the sum of squares -// of the elements of Abar. -// If damp is small and if the columns of A -// have all been scaled to have length 1.0, -// anorm should increase to roughly sqrt(n). -// A radically different value for anorm may -// indicate an error in subroutine aprod (there -// may be an inconsistency between modes 1 and 2). -// -// acond output An estimate of cond(Abar), the condition -// number of Abar. A very high value of acond -// may again indicate an error in aprod. -// -// rnorm output An estimate of the final value of norm(rbar), -// the function being minimized (see notation -// above). This will be small if A*x = b has -// a solution. -// -// arnorm output An estimate of the final value of -// norm( Abar(transpose)*rbar ), the norm of -// the residual for the usual normal equations. -// This should be small in all cases. (arnorm -// will often be smaller than the true value -// computed from the output vector x.) -// -// xnorm output An estimate of the norm of the final -// solution vector x. -// -// -// Subroutines and functions used -// ------------------------------ -// -// USER aprod -// CBLAS dcopy, dnrm2, dscal (see Lawson et al. below) -// -// -// References -// ---------- -// -// C.C. Paige and M.A. Saunders, LSQR: An algorithm for sparse -// linear equations and sparse least squares, -// ACM Transactions on Mathematical Software 8, 1 (March 1982), -// pp. 43-71. -// -// C.C. Paige and M.A. Saunders, Algorithm 583, LSQR: Sparse -// linear equations and least-squares problems, -// ACM Transactions on Mathematical Software 8, 2 (June 1982), -// pp. 195-209. -// -// C.L. Lawson, R.J. Hanson, D.R. Kincaid and F.T. Krogh, -// Basic linear algebra subprograms for Fortran usage, -// ACM Transactions on Mathematical Software 5, 3 (Sept 1979), -// pp. 308-323 and 324-325. -// ------------------------------------------------------------------ -// -// -// LSQR development: -// 22 Feb 1982: LSQR sent to ACM TOMS to become Algorithm 583. -// 15 Sep 1985: Final F66 version. LSQR sent to "misc" in netlib. -// 13 Oct 1987: Bug (Robert Davies, DSIR). Have to delete -// if ( (one + dabs(t)) .le. one ) GO TO 200 -// from loop 200. The test was an attempt to reduce -// underflows, but caused w(i) not to be updated. -// 17 Mar 1989: First F77 version. -// 04 May 1989: Bug (David Gay, AT&T). When the second beta is zero, -// rnorm = 0 and -// test2 = arnorm / (anorm * rnorm) overflows. -// Fixed by testing for rnorm = 0. -// 05 May 1989: Sent to "misc" in netlib. -// 14 Mar 1990: Bug (John Tomlin via IBM OSL testing). -// Setting rhbar2 = rhobar**2 + dampsq can give zero -// if rhobar underflows and damp = 0. -// Fixed by testing for damp = 0 specially. -// 15 Mar 1990: Converted to lower case. -// 21 Mar 1990: d2norm introduced to avoid overflow in numerous -// items like c = sqrt( a**2 + b**2 ). -// 04 Sep 1991: wantse added as an argument to LSQR, to make -// standard errors optional. This saves storage and -// time when se(*) is not wanted. -// 13 Feb 1992: istop now returns a value in [1,5], not [1,7]. -// 1, 2 or 3 means that x solves one of the problems -// Ax = b, min norm(Ax - b) or damped least squares. -// 4 means the limit on cond(A) was reached. -// 5 means the limit on iterations was reached. -// 07 Dec 1994: Keep track of dxmax = max_k norm( phi_k * d_k ). -// So far, this is just printed at the end. -// A large value (relative to norm(x)) indicates -// significant cancellation in forming -// x = D*f = sum( phi_k * d_k ). -// A large column of D need NOT be serious if the -// corresponding phi_k is small. -// 27 Dec 1994: Include estimate of alfa_opt in iteration log. -// alfa_opt is the optimal scale factor for the -// residual in the "augmented system", as described by -// A. Bjorck (1992), -// Pivoting and stability in the augmented system method, -// in D. F. Griffiths and G. A. Watson (eds.), -// "Numerical Analysis 1991", -// Proceedings of the 14th Dundee Conference, -// Pitman Research Notes in Mathematics 260, -// Longman Scientific and Technical, Harlow, Essex, 1992. -// 14 Apr 2006: "Line-by-line" conversion to ISO C by -// Michael P. Friedlander. -// -// -// Michael A. Saunders mike@sol-michael.stanford.edu -// Dept of Operations Research na.Msaunders@na-net.ornl.gov -// Stanford University -// Stanford, CA 94305-4022 (415) 723-1875 -//----------------------------------------------------------------------- +void lsqr( + long int m, + long int n, + // void (*aprod)(int mode, int m, int n, double x[], double y[], + // void *UsrWrk), + double damp, + // void *UsrWrk, + double *knownTerms, // len = m reported as u + double *vVect, // len = n reported as v + double *wVect, // len = n reported as w + double *xSolution, // len = n reported as x + double *standardError, // len at least n. May be NULL. reported as se + double atol, + double btol, + double conlim, + int itnlim, + // The remaining variables are output only. + int *istop_out, + int *itn_out, + double *anorm_out, + double *acond_out, + double *rnorm_out, + double *arnorm_out, + double *xnorm_out, + double *systemMatrix, // reported as a + long int *matrixIndex, // reported as janew + int *instrCol, + int *instrConstrIlung, + double *preCondVect, + struct comData comlsqr) + { + // ------------------------------------------------------------------ + // + // LSQR finds a solution x to the following problems: + // + // 1. Unsymmetric equations -- solve A*x = b + // + // 2. Linear least squares -- solve A*x = b + // in the least-squares sense + // + // 3. Damped least squares -- solve ( A )*x = ( b ) + // ( damp*I ) ( 0 ) + // in the least-squares sense + // + // where A is a matrix with m rows and n columns, b is an + // m-vector, and damp is a scalar. (All quantities are real.) + // The matrix A is intended to be large and sparse. It is accessed + // by means of subroutine calls of the form + // + // aprod ( mode, m, n, x, y, UsrWrk ) + // + // which must perform the following functions: + // + // If mode = 1, compute y = y + A*x. + // If mode = 2, compute x = x + A(transpose)*y. + // + // The vectors x and y are input parameters in both cases. + // If mode = 1, y should be altered without changing x. + // If mode = 2, x should be altered without changing y. + // The parameter UsrWrk may be used for workspace as described + // below. + // + // The rhs vector b is input via u, and subsequently overwritten. + // + // + // Note: LSQR uses an iterative method to approximate the solution. + // The number of iterations required to reach a certain accuracy + // depends strongly on the scaling of the problem. Poor scaling of + // the rows or columns of A should therefore be avoided where + // possible. + // + // For example, in problem 1 the solution is unaltered by + // row-scaling. If a row of A is very small or large compared to + // the other rows of A, the corresponding row of ( A b ) should be + // scaled up or down. + // + // In problems 1 and 2, the solution x is easily recovered + // following column-scaling. Unless better information is known, + // the nonzero columns of A should be scaled so that they all have + // the same Euclidean norm (e.g., 1.0). + // + // In problem 3, there is no freedom to re-scale if damp is + // nonzero. However, the value of damp should be assigned only + // after attention has been paid to the scaling of A. + // + // The parameter damp is intended to help regularize + // ill-conditioned systems, by preventing the true solution from + // being very large. Another aid to regularization is provided by + // the parameter acond, which may be used to terminate iterations + // before the computed solution becomes very large. + // + // Note that x is not an input parameter. + // If some initial estimate x0 is known and if damp = 0, + // one could proceed as follows: + // + // 1. Compute a residual vector r0 = b - A*x0. + // 2. Use LSQR to solve the system A*dx = r0. + // 3. Add the correction dx to obtain a final solution x = x0 + dx. + // + // This requires that x0 be available before and after the call + // to LSQR. To judge the benefits, suppose LSQR takes k1 iterations + // to solve A*x = b and k2 iterations to solve A*dx = r0. + // If x0 is "good", norm(r0) will be smaller than norm(b). + // If the same stopping tolerances atol and btol are used for each + // system, k1 and k2 will be similar, but the final solution x0 + dx + // should be more accurate. The only way to reduce the total work + // is to use a larger stopping tolerance for the second system. + // If some value btol is suitable for A*x = b, the larger value + // btol*norm(b)/norm(r0) should be suitable for A*dx = r0. + // + // Preconditioning is another way to reduce the number of iterations. + // If it is possible to solve a related system M*x = b efficiently, + // where M approximates A in some helpful way + // (e.g. M - A has low rank or its elements are small relative to + // those of A), LSQR may converge more rapidly on the system + // A*M(inverse)*z = b, + // after which x can be recovered by solving M*x = z. + // + // NOTE: If A is symmetric, LSQR should not be used! + // Alternatives are the symmetric conjugate-gradient method (cg) + // and/or SYMMLQ. + // SYMMLQ is an implementation of symmetric cg that applies to + // any symmetric A and will converge more rapidly than LSQR. + // If A is positive definite, there are other implementations of + // symmetric cg that require slightly less work per iteration + // than SYMMLQ (but will take the same number of iterations). + // + // + // Notation + // -------- + // + // The following quantities are used in discussing the subroutine + // parameters: + // + // Abar = ( A ), bbar = ( b ) + // ( damp*I ) ( 0 ) + // + // r = b - A*x, rbar = bbar - Abar*x + // + // rnorm = sqrt( norm(r)**2 + damp**2 * norm(x)**2 ) + // = norm( rbar ) + // + // relpr = the relative precision of floating-point arithmetic + // on the machine being used. On most machines, + // relpr is about 1.0e-7 and 1.0d-16 in single and double + // precision respectively. + // + // LSQR minimizes the function rnorm with respect to x. + // + // + // Parameters + // ---------- + // + // m input m, the number of rows in A. + // + // n input n, the number of columns in A. + // + // aprod external See above. + // + // damp input The damping parameter for problem 3 above. + // (damp should be 0.0 for problems 1 and 2.) + // If the system A*x = b is incompatible, values + // of damp in the range 0 to sqrt(relpr)*norm(A) + // will probably have a negligible effect. + // Larger values of damp will tend to decrease + // the norm of x and reduce the number of + // iterations required by LSQR. + // + // The work per iteration and the storage needed + // by LSQR are the same for all values of damp. + // + // rw workspace Transit pointer to user's workspace. + // Note: LSQR does not explicitly use this + // parameter, but passes it to subroutine aprod for + // possible use as workspace. + // + // u(m) input The rhs vector b. Beware that u is + // over-written by LSQR. + // + // v(n) workspace + // + // w(n) workspace + // + // x(n) output Returns the computed solution x. + // + // se(*) output If m .gt. n or damp .gt. 0, the system is + // (maybe) overdetermined and the standard errors may be + // useful. (See the first LSQR reference.) + // Otherwise (m .le. n and damp = 0) they do not + // mean much. Some time and storage can be saved + // by setting se = NULL. In that case, se will + // not be touched. + // + // If se is not NULL, then the dimension of se must + // be n or more. se(1:n) then returns standard error + // estimates for the components of x. + // For each i, se(i) is set to the value + // rnorm * sqrt( sigma(i,i) / t ), + // where sigma(i,i) is an estimate of the i-th + // diagonal of the inverse of Abar(transpose)*Abar + // and t = 1 if m .le. n, + // t = m - n if m .gt. n and damp = 0, + // t = m if damp .ne. 0. + // + // atol input An estimate of the relative error in the data + // defining the matrix A. For example, + // if A is accurate to about 6 digits, set + // atol = 1.0e-6 . + // + // btol input An estimate of the relative error in the data + // defining the rhs vector b. For example, + // if b is accurate to about 6 digits, set + // btol = 1.0e-6 . + // + // conlim input An upper limit on cond(Abar), the apparent + // condition number of the matrix Abar. + // Iterations will be terminated if a computed + // estimate of cond(Abar) exceeds conlim. + // This is intended to prevent certain small or + // zero singular values of A or Abar from + // coming into effect and causing unwanted growth + // in the computed solution. + // + // conlim and damp may be used separately or + // together to regularize ill-conditioned systems. + // + // Normally, conlim should be in the range + // 1000 to 1/relpr. + // Suggested value: + // conlim = 1/(100*relpr) for compatible systems, + // conlim = 1/(10*sqrt(relpr)) for least squares. + // + // Note: If the user is not concerned about the parameters + // atol, btol and conlim, any or all of them may be set + // to zero. The effect will be the same as the values + // relpr, relpr and 1/relpr respectively. + // + // itnlim input An upper limit on the number of iterations. + // Suggested value: + // itnlim = n/2 for well-conditioned systems + // with clustered singular values, + // itnlim = 4*n otherwise. + // + // nout input File number for printed output. If positive, + // a summary will be printed on file nout. + // + // istop output An integer giving the reason for termination: + // + // 0 x = 0 is the exact solution. + // No iterations were performed. + // + // 1 The equations A*x = b are probably + // compatible. Norm(A*x - b) is sufficiently + // small, given the values of atol and btol. + // + // 2 damp is zero. The system A*x = b is probably + // not compatible. A least-squares solution has + // been obtained that is sufficiently accurate, + // given the value of atol. + // + // 3 damp is nonzero. A damped least-squares + // solution has been obtained that is sufficiently + // accurate, given the value of atol. + // + // 4 An estimate of cond(Abar) has exceeded + // conlim. The system A*x = b appears to be + // ill-conditioned. Otherwise, there could be an + // error in subroutine aprod. + // + // 5 The iteration limit itnlim was reached. + // + // itn output The number of iterations performed. + // + // anorm output An estimate of the Frobenius norm of Abar. + // This is the square-root of the sum of squares + // of the elements of Abar. + // If damp is small and if the columns of A + // have all been scaled to have length 1.0, + // anorm should increase to roughly sqrt(n). + // A radically different value for anorm may + // indicate an error in subroutine aprod (there + // may be an inconsistency between modes 1 and 2). + // + // acond output An estimate of cond(Abar), the condition + // number of Abar. A very high value of acond + // may again indicate an error in aprod. + // + // rnorm output An estimate of the final value of norm(rbar), + // the function being minimized (see notation + // above). This will be small if A*x = b has + // a solution. + // + // arnorm output An estimate of the final value of + // norm( Abar(transpose)*rbar ), the norm of + // the residual for the usual normal equations. + // This should be small in all cases. (arnorm + // will often be smaller than the true value + // computed from the output vector x.) + // + // xnorm output An estimate of the norm of the final + // solution vector x. + // + // + // Subroutines and functions used + // ------------------------------ + // + // USER aprod + // CBLAS dcopy, dnrm2, dscal (see Lawson et al. below) + // + // + // References + // ---------- + // + // C.C. Paige and M.A. Saunders, LSQR: An algorithm for sparse + // linear equations and sparse least squares, + // ACM Transactions on Mathematical Software 8, 1 (March 1982), + // pp. 43-71. + // + // C.C. Paige and M.A. Saunders, Algorithm 583, LSQR: Sparse + // linear equations and least-squares problems, + // ACM Transactions on Mathematical Software 8, 2 (June 1982), + // pp. 195-209. + // + // C.L. Lawson, R.J. Hanson, D.R. Kincaid and F.T. Krogh, + // Basic linear algebra subprograms for Fortran usage, + // ACM Transactions on Mathematical Software 5, 3 (Sept 1979), + // pp. 308-323 and 324-325. + // ------------------------------------------------------------------ + // + // + // LSQR development: + // 22 Feb 1982: LSQR sent to ACM TOMS to become Algorithm 583. + // 15 Sep 1985: Final F66 version. LSQR sent to "misc" in netlib. + // 13 Oct 1987: Bug (Robert Davies, DSIR). Have to delete + // if ( (one + dabs(t)) .le. one ) GO TO 200 + // from loop 200. The test was an attempt to reduce + // underflows, but caused w(i) not to be updated. + // 17 Mar 1989: First F77 version. + // 04 May 1989: Bug (David Gay, AT&T). When the second beta is zero, + // rnorm = 0 and + // test2 = arnorm / (anorm * rnorm) overflows. + // Fixed by testing for rnorm = 0. + // 05 May 1989: Sent to "misc" in netlib. + // 14 Mar 1990: Bug (John Tomlin via IBM OSL testing). + // Setting rhbar2 = rhobar**2 + dampsq can give zero + // if rhobar underflows and damp = 0. + // Fixed by testing for damp = 0 specially. + // 15 Mar 1990: Converted to lower case. + // 21 Mar 1990: d2norm introduced to avoid overflow in numerous + // items like c = sqrt( a**2 + b**2 ). + // 04 Sep 1991: wantse added as an argument to LSQR, to make + // standard errors optional. This saves storage and + // time when se(*) is not wanted. + // 13 Feb 1992: istop now returns a value in [1,5], not [1,7]. + // 1, 2 or 3 means that x solves one of the problems + // Ax = b, min norm(Ax - b) or damped least squares. + // 4 means the limit on cond(A) was reached. + // 5 means the limit on iterations was reached. + // 07 Dec 1994: Keep track of dxmax = max_k norm( phi_k * d_k ). + // So far, this is just printed at the end. + // A large value (relative to norm(x)) indicates + // significant cancellation in forming + // x = D*f = sum( phi_k * d_k ). + // A large column of D need NOT be serious if the + // corresponding phi_k is small. + // 27 Dec 1994: Include estimate of alfa_opt in iteration log. + // alfa_opt is the optimal scale factor for the + // residual in the "augmented system", as described by + // A. Bjorck (1992), + // Pivoting and stability in the augmented system method, + // in D. F. Griffiths and G. A. Watson (eds.), + // "Numerical Analysis 1991", + // Proceedings of the 14th Dundee Conference, + // Pitman Research Notes in Mathematics 260, + // Longman Scientific and Technical, Harlow, Essex, 1992. + // 14 Apr 2006: "Line-by-line" conversion to ISO C by + // Michael P. Friedlander. + // + // + // Michael A. Saunders mike@sol-michael.stanford.edu + // Dept of Operations Research na.Msaunders@na-net.ornl.gov + // Stanford University + // Stanford, CA 94305-4022 (415) 723-1875 + //----------------------------------------------------------------------- + + // Local copies of output variables. Output vars are assigned at exit. -// Local copies of output variables. Output vars are assigned at exit. + + + - int - istop = 0, - itn = 0; - double - anorm = ZERO, - acond = ZERO, - rnorm = ZERO, - arnorm = ZERO, - xnorm = ZERO; - + + + int istop = 0; + int itn = 0; + + +double + anorm = ZERO, + acond = ZERO, + rnorm = ZERO, + arnorm = ZERO, + xnorm = ZERO; + // Local variables - const bool - extra = false, // true for extra printing below. - damped = damp > ZERO, - wantse = standardError != NULL; - long int i; - int - maxdx, nconv, nstop; - double - alfopt, alpha, arnorm0, beta, bnorm, - cs, cs1, cs2, ctol, - delta, dknorm, dknormSum, dnorm, dxk, dxmax, - gamma, gambar, phi, phibar, psi, - res2, rho, rhobar, rhbar1, - rhs, rtol, sn, sn1, sn2, - t, tau, temp, test1, test2, test3, - theta, t1, t2, t3, xnorm1, z, zbar; - char - enter[] = "Enter LSQR. ", - exitLsqr[] = "Exit LSQR. ", - msg[6][100] = +const bool + extra = false, // true for extra printing below. + damped = damp > ZERO, + wantse = standardError != NULL; +long int i; +int + maxdx, + nconv, nstop; +double + alfopt, + alpha, arnorm0, beta, bnorm, + cs, cs1, cs2, ctol, + delta, dknorm, dknormSum, dnorm, dxk, dxmax, + gamma, gambar, phi, phibar, psi, + res2, rho, rhobar, rhbar1, + rhs, rtol, sn, sn1, sn2, + t, tau, temp, test1, test2, test3, + theta, t1, t2, t3, xnorm1, z, zbar; +char + enter[] = "Enter LSQR. ", + exitLsqr[] = "Exit LSQR. ", + msg[6][100] = { {"The exact solution is x = 0"}, {"A solution to Ax = b was found, given atol, btol"}, {"A least-squares solution was found, given atol"}, {"A damped least-squares solution was found, given atol"}, {"Cond(Abar) seems to be too large, given conlim"}, - {"The iteration limit was reached"} - }; - char lsqrOut[] = "lsqr-output"; // (buffer flush problem) - char wpath[1024]; - size_t sizePath=1020; - + {"The iteration limit was reached"}}; +char lsqrOut[] = "lsqr-output"; // (buffer flush problem) +char wpath[1024]; +size_t sizePath = 1020; + //----------------------------------------------------------------------- // Format strings. - char fmt_1000[] = - " %s Least-squares solution of Ax = b\n" - " The matrix A has %ld rows and %ld columns\n" - " damp = %-22.2e wantse = %10i\n" - " atol = %-22.2e conlim = %10.2e\n" - " btol = %-22.2e itnlim = %10d\n\n"; - char fmt_1200[] = - " Itn x(1) Function" - " Compatible LS Norm A Cond A\n"; - char fmt_1300[] = - " Itn x(1) Function" - " Compatible LS Norm Abar Cond Abar\n"; - char fmt_1400[] = - " phi dknorm dxk alfa_opt\n"; - char fmt_1500_extra[] = - " %6d %16.9e %16.9e %9.2e %9.2e %8.1e %8.1e %8.1e %7.1e %7.1e %7.1e\n"; - char fmt_1500[] = - " %6d %16.9e %16.9e %9.2e %9.2e %8.1e %8.1e\n"; - char fmt_1550[] = - " %6d %16.9e %16.9e %9.2e %9.2e\n"; - char fmt_1600[] = - "\n"; - char fmt_2000[] = - "\n" - " %s istop = %-10d itn = %-10d\n" - " %s anorm = %11.5e acond = %11.5e\n" - " %s vnorm = %11.5e xnorm = %11.5e\n" - " %s rnorm = %11.5e arnorm = %11.5e\n"; - char fmt_2100[] = - " %s max dx = %7.1e occured at itn %-9d\n" - " %s = %7.1e*xnorm\n"; - char fmt_3000[] = - " %s %s\n"; +char fmt_1000[] = + " %s Least-squares solution of Ax = b\n" + " The matrix A has %ld rows and %ld columns\n" + " damp = %-22.2e wantse = %10i\n" + " atol = %-22.2e conlim = %10.2e\n" + " btol = %-22.2e itnlim = %10d\n\n"; +char fmt_1200[] = + " Itn x(1) Function" + " Compatible LS Norm A Cond A\n"; +char fmt_1300[] = + " Itn x(1) Function" + " Compatible LS Norm Abar Cond Abar\n"; +char fmt_1400[] = + " phi dknorm dxk alfa_opt\n"; +char fmt_1500_extra[] = + " %6d %16.9e %16.9e %9.2e %9.2e %8.1e %8.1e %8.1e %7.1e %7.1e %7.1e\n"; +char fmt_1500[] = + " %6d %16.9e %16.9e %9.2e %9.2e %8.1e %8.1e\n"; +char fmt_1550[] = + " %6d %16.9e %16.9e %9.2e %9.2e\n"; +char fmt_1600[] = + "\n"; +char fmt_2000[] = + "\n" + " %s istop = %-10d itn = %-10d\n" + " %s anorm = %11.5e acond = %11.5e\n" + " %s vnorm = %11.5e xnorm = %11.5e\n" + " %s rnorm = %11.5e arnorm = %11.5e\n"; +char fmt_2100[] = + " %s max dx = %7.1e occured at itn %-9d\n" + " %s = %7.1e*xnorm\n"; +char fmt_3000[] = + " %s %s\n"; ///////////// Specific definitions - time_t startCycleTime,endCycleTime,totTime,partialTime,CPRtimeStart,CPRtimeEnd,ompSec=0; - int writeCPR; //=0 no write CPR, =1 write CPR and continue, =2 write CPR and return - int noCPR; - int myid,nproc; - long int *mapNoss, *mapNcoeff; - MPI_Status status; - long int nunkSplit, localAstro, localAstroMax, other; - int nAstroElements; - int debugMode; - long VrIdAstroPDim, VrIdAstroPDimMax; - long nDegFreedomAtt; - int nAttAxes; - int nAttParam,nInstrParam,nGlobalParam,itnTest,nAttP,numOfExtStar,numOfBarStar,numOfExtAttCol,nobs; - long mapNossBefore; - short nAstroPSolved,nInstrPsolved; - double cycleStartMpiTime, cycleEndMpiTime; - double *vAuxVect; - int CPRCount; - FILE *fpCPRend, *nout, *fpItnLimitNew; - int nEqExtConstr,nEqBarConstr; - int nElemIC,nOfInstrConstr; - double *kAuxcopy; - double *kcopy; -//////////////////////////////// +time_t startCycleTime, endCycleTime, totTime, partialTime, CPRtimeStart, CPRtimeEnd, ompSec = 0; +int writeCPR; //=0 no write CPR, =1 write CPR and continue, =2 write CPR and return +int noCPR; +int myid, nproc; +long int *mapNoss, *mapNcoeff; +MPI_Status status; +long int nunkSplit, localAstro, localAstroMax, other; +int nAstroElements; +int debugMode; +long VrIdAstroPDim, VrIdAstroPDimMax; +long nDegFreedomAtt; +int nAttAxes; +int nAttParam, nInstrParam, nGlobalParam, itnTest, nAttP, numOfExtStar, numOfBarStar, numOfExtAttCol, nobs; +long mapNossBefore; +short nAstroPSolved, nInstrPsolved; +double cycleStartMpiTime, cycleEndMpiTime; +double *vAuxVect; +int CPRCount; +FILE *fpCPRend, *nout, *fpItnLimitNew; +int nEqExtConstr, nEqBarConstr; +int nElemIC, nOfInstrConstr; +double *kAuxcopy; +double *kcopy; +int ntasks; +int nthreads; +//////////////////////////////// // Initialize. -myid=comlsqr.myid; -nproc=comlsqr.nproc; -mapNcoeff=comlsqr.mapNcoeff; -mapNoss=comlsqr.mapNoss; -nAttParam=comlsqr.nAttParam; -nInstrParam=comlsqr.nInstrParam; -nGlobalParam=comlsqr.nGlobalParam; -nunkSplit=comlsqr.nunkSplit; -VrIdAstroPDim=comlsqr.VrIdAstroPDim; -VrIdAstroPDimMax=comlsqr.VrIdAstroPDimMax; -nAstroPSolved=comlsqr.nAstroPSolved; -nEqExtConstr=comlsqr.nEqExtConstr; -nEqBarConstr=comlsqr.nEqBarConstr; -nDegFreedomAtt=comlsqr.nDegFreedomAtt; -nAttAxes=comlsqr.nAttAxes; -localAstro= VrIdAstroPDim*nAstroPSolved; -localAstroMax=VrIdAstroPDimMax*nAstroPSolved; -numOfExtStar=comlsqr.numOfExtStar; -numOfBarStar=comlsqr.numOfBarStar; -nAttP=comlsqr.nAttP; -numOfExtAttCol=comlsqr.numOfExtAttCol; -mapNossBefore=comlsqr.mapNossBefore; -nobs=comlsqr.nobs; -debugMode=comlsqr.debugMode; -noCPR=comlsqr.noCPR; -nElemIC=comlsqr.nElemIC; -nOfInstrConstr=comlsqr.nOfInstrConstr; -nInstrPsolved=comlsqr.nInstrPSolved; - -other=(long)nAttParam + nInstrParam + nGlobalParam; -if(nAstroPSolved) vAuxVect=(double *) calloc(localAstroMax,sizeof(double)); - -comlsqr.itn=itn; -totTime=comlsqr.totSec; -partialTime=comlsqr.totSec; - - if(debugMode){ - for(long i=0; i<mapNoss[myid]+nEqExtConstr+nEqBarConstr+nOfInstrConstr;i++){ - printf("PE=%d Knowterms[%d]=%e\n",myid,i,knownTerms[i]); +myid = comlsqr.myid; +nproc = comlsqr.nproc; +mapNcoeff = comlsqr.mapNcoeff; +mapNoss = comlsqr.mapNoss; +nAttParam = comlsqr.nAttParam; +nInstrParam = comlsqr.nInstrParam; +nGlobalParam = comlsqr.nGlobalParam; +nunkSplit = comlsqr.nunkSplit; +VrIdAstroPDim = comlsqr.VrIdAstroPDim; +VrIdAstroPDimMax = comlsqr.VrIdAstroPDimMax; +nAstroPSolved = comlsqr.nAstroPSolved; +nEqExtConstr = comlsqr.nEqExtConstr; +nEqBarConstr = comlsqr.nEqBarConstr; +nDegFreedomAtt = comlsqr.nDegFreedomAtt; +nAttAxes = comlsqr.nAttAxes; +localAstro = VrIdAstroPDim * nAstroPSolved; +localAstroMax = VrIdAstroPDimMax * nAstroPSolved; +numOfExtStar = comlsqr.numOfExtStar; +numOfBarStar = comlsqr.numOfBarStar; +nAttP = comlsqr.nAttP; +numOfExtAttCol = comlsqr.numOfExtAttCol; +mapNossBefore = comlsqr.mapNossBefore; +nobs = comlsqr.nobs; +debugMode = comlsqr.debugMode; +noCPR = comlsqr.noCPR; +nElemIC = comlsqr.nElemIC; +nOfInstrConstr = comlsqr.nOfInstrConstr; +nInstrPsolved = comlsqr.nInstrPSolved; +ntasks= comlsqr.ntasks; +nthreads= comlsqr.nthreads; + + other = (long)nAttParam + nInstrParam + nGlobalParam; +if (nAstroPSolved) + vAuxVect = (double *)calloc(localAstroMax, sizeof(double)); + +comlsqr.itn = itn; +totTime = comlsqr.totSec; +partialTime = comlsqr.totSec; + +if (debugMode) +{ + for (long i = 0; i < mapNoss[myid] + nEqExtConstr + nEqBarConstr + nOfInstrConstr; i++) + { + printf("PE=%d Knowterms[%d]=%e\n", myid, i, knownTerms[i]); } - int nStar=comlsqr.nStar; - int c1=0; - int colix=0; - for(int j=0;j<mapNoss[myid];j++) - for(int i=0; i<nAstroPSolved+nAttP;i++){ - if(i==0) colix=matrixIndex[j*2]; - else if(i==nAstroPSolved) colix=matrixIndex[j*2+1]; - else if (i==nAstroPSolved+nAttP/nAttAxes) colix=matrixIndex[j*2+1]+nDegFreedomAtt; - else if (i==nAstroPSolved+2*nAttP/nAttAxes) colix=matrixIndex[j*2+1]+2*nDegFreedomAtt; - else colix++; - printf("PE=%d systemMatrix[%ld][%d]=%f\n",myid,mapNossBefore+j,colix,systemMatrix[c1]); + int nStar = comlsqr.nStar; + int c1 = 0; + int colix = 0; + for (int j = 0; j < mapNoss[myid]; j++) + for (int i = 0; i < nAstroPSolved + nAttP; i++) + { + if (i == 0) + colix = matrixIndex[j * 2]; + else if (i == nAstroPSolved) + colix = matrixIndex[j * 2 + 1]; + else if (i == nAstroPSolved + nAttP / nAttAxes) + colix = matrixIndex[j * 2 + 1] + nDegFreedomAtt; + else if (i == nAstroPSolved + 2 * nAttP / nAttAxes) + colix = matrixIndex[j * 2 + 1] + 2 * nDegFreedomAtt; + else + colix++; + printf("PE=%d systemMatrix[%ld][%d]=%f\n", myid, mapNossBefore + j, colix, systemMatrix[c1]); c1++; } - for(int k=0;k<nEqExtConstr;k++) - for(int i=0; i<numOfExtStar*nAstroPSolved+numOfExtAttCol*nAttAxes;i++){ - printf("PE=%d systemMatrix[%d][%ld]=%f\n",myid,nobs+k,i-mapNcoeff[myid],systemMatrix[c1]); + for (int k = 0; k < nEqExtConstr; k++) + for (int i = 0; i < numOfExtStar * nAstroPSolved + numOfExtAttCol * nAttAxes; i++) + { + printf("PE=%d systemMatrix[%d][%ld]=%f\n", myid, nobs + k, i - mapNcoeff[myid], systemMatrix[c1]); c1++; } - for(int k=0;k<nEqBarConstr;k++) - for(int i=0; i<numOfBarStar*nAstroPSolved;i++){ - printf("PE=%d systemMatrix[%d][%ld]=%f\n",myid,nobs+k,i-mapNcoeff[myid],systemMatrix[c1]); + for (int k = 0; k < nEqBarConstr; k++) + for (int i = 0; i < numOfBarStar * nAstroPSolved; i++) + { + printf("PE=%d systemMatrix[%d][%ld]=%f\n", myid, nobs + k, i - mapNcoeff[myid], systemMatrix[c1]); c1++; } - int counter=0; - for(int k=0;k<nOfInstrConstr;k++) - for(int j=0;j<instrConstrIlung[k];j++){ - printf("PE=%d systemMatrix[%d][%ld]=%f\n",myid,nobs+nEqExtConstr+k,instrCol[mapNoss[myid]*nInstrPsolved+counter],systemMatrix[c1]); - counter++; - c1++; - } - } - -if(myid==0) + int counter = 0; + for (int k = 0; k < nOfInstrConstr; k++) + for (int j = 0; j < instrConstrIlung[k]; j++) + { + printf("PE=%d systemMatrix[%d][%ld]=%f\n", myid, nobs + nEqExtConstr + k, instrCol[mapNoss[myid] * nInstrPsolved + counter], systemMatrix[c1]); + counter++; + c1++; + } +} + +if (myid == 0) { - nout=fopen(lsqrOut,"a"); + nout = fopen(lsqrOut, "a"); if (nout != NULL) fprintf(nout, fmt_1000, enter, m, n, damp, wantse, atol, conlim, btol, itnlim); - else { - printf("Error while opening %s (1)\n",lsqrOut); - MPI_Abort(MPI_COMM_WORLD,1); + else + { + printf("Error while opening %s (1)\n", lsqrOut); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); - } - fclose(nout); + } + fclose(nout); } -itn = 0; -istop = 0; -nstop = 0; -maxdx = 0; -ctol = ZERO; -if (conlim > ZERO) ctol = ONE / conlim; -anorm = ZERO; -acond = ZERO; -dnorm = ZERO; -dxmax = ZERO; -res2 = ZERO; -psi = ZERO; -xnorm = ZERO; -xnorm1 = ZERO; -cs2 = - ONE; -sn2 = ZERO; -z = ZERO; - -CPRCount=0; +itn = 0; +istop = 0; +nstop = 0; +maxdx = 0; +ctol = ZERO; +if (conlim > ZERO) + ctol = ONE / conlim; +anorm = ZERO; +acond = ZERO; +dnorm = ZERO; +dxmax = ZERO; +res2 = ZERO; +psi = ZERO; +xnorm = ZERO; +xnorm1 = ZERO; +cs2 = -ONE; +sn2 = ZERO; +z = ZERO; + + + + +CPRCount = 0; // ------------------------------------------------------------------ // Set up the first vectors u and v for the bidiagonalization. // These satisfy beta*u = b, alpha*v = A(transpose)*u. // ------------------------------------------------------------------ -dload( nunkSplit, 0.0, vVect ); -dload( nunkSplit, 0.0, xSolution ); -if ( wantse ) - dload( nunkSplit, 0.0, standardError ); -alpha = ZERO; +dload(nunkSplit, 0.0, vVect); +dload(nunkSplit, 0.0, xSolution); +if (wantse) + dload(nunkSplit, 0.0, standardError); +alpha = ZERO; // Find the maximum value on u - double betaLoc; - if(myid==0) betaLoc=cblas_dnrm2(mapNoss[myid]+nEqExtConstr+nEqBarConstr+nOfInstrConstr,knownTerms,1); - else betaLoc=cblas_dnrm2(mapNoss[myid],knownTerms,1); +double betaLoc; +if (myid == 0) + betaLoc = cblas_dnrm2(mapNoss[myid] + nEqExtConstr + nEqBarConstr + nOfInstrConstr, knownTerms, 1); +else + betaLoc = cblas_dnrm2(mapNoss[myid], knownTerms, 1); -double betaLoc2=betaLoc*betaLoc; +double betaLoc2 = betaLoc * betaLoc; double betaGlob; -MPI_Allreduce(&betaLoc2, &betaGlob,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); -beta=sqrt(betaGlob); -if (beta > ZERO) +MPI_Allreduce(&betaLoc2, &betaGlob, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +beta = sqrt(betaGlob); +if (beta > ZERO) { - cblas_dscal ( mapNoss[myid]+nEqExtConstr+nEqBarConstr+nOfInstrConstr, (ONE / beta), knownTerms, 1 ); - MPI_Barrier(MPI_COMM_WORLD); + cblas_dscal(mapNoss[myid] + nEqExtConstr + nEqBarConstr + nOfInstrConstr, (ONE / beta), knownTerms, 1); + + MPI_Barrier(MPI_COMM_WORLD); //only processor 0 accumulate and distribute the v array -#pragma omp for - for(i=0;i<localAstroMax;i++) +//// + + // FV EDIT + //#pragma omp for + for (i = 0; i < localAstroMax; i++) + { + vAuxVect[i] = vVect[i]; + vVect[i] = 0; + } + if (myid != 0) { - vAuxVect[i]=vVect[i]; - vVect[i]=0; - } - if(myid!=0) - { -#pragma omp for - for(i=localAstroMax;i<nunkSplit;i++) vVect[i]=0; - } - aprod ( 2, m, n, vVect, knownTerms, systemMatrix, matrixIndex, instrCol,instrConstrIlung,comlsqr,&ompSec ); - - MPI_Barrier(MPI_COMM_WORLD); + // FV EDIT + //#pragma omp for + for (i = localAstroMax; i < nunkSplit; i++) + vVect[i] = 0; + } + + + //printf("PRIMA vVect[1]: %f:\n", vVect[1] ); + + aprod(2, m, n, vVect, knownTerms, systemMatrix, matrixIndex, instrCol, instrConstrIlung, comlsqr, &ompSec ); + // printf("DOPO vVect[1]: %f:\n", vVect[1] ); + + + + + + + MPI_Barrier(MPI_COMM_WORLD); double *dcopy; - dcopy=(double *)calloc(comlsqr.nAttParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - mpi_allreduce(&vVect[localAstroMax],dcopy,(long int) comlsqr.nAttParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); -#pragma omp for - for(i=0;i<comlsqr.nAttParam;i++) + dcopy = (double *)calloc(comlsqr.nAttParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + mpi_allreduce(&vVect[localAstroMax], dcopy, (long int)comlsqr.nAttParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // FV EDIT + //#pragma omp for + for (i = 0; i < comlsqr.nAttParam; i++) { - vVect[localAstroMax+i]=dcopy[i]; - } - free(dcopy); - dcopy=(double *)calloc(comlsqr.nInstrParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - - mpi_allreduce(&vVect[localAstroMax+comlsqr.nAttParam],dcopy,(long int) comlsqr.nInstrParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); -#pragma omp for - for(i=0;i<comlsqr.nInstrParam;i++) + vVect[localAstroMax + i] = dcopy[i]; + } + free(dcopy); + dcopy = (double *)calloc(comlsqr.nInstrParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + + mpi_allreduce(&vVect[localAstroMax + comlsqr.nAttParam], dcopy, (long int)comlsqr.nInstrParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // FV EDIT + //#pragma omp for + for (i = 0; i < comlsqr.nInstrParam; i++) { - vVect[localAstroMax+comlsqr.nAttParam+i]=dcopy[i]; - } - free(dcopy); - dcopy=(double *)calloc(comlsqr.nGlobalParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - MPI_Allreduce(&vVect[localAstroMax+comlsqr.nAttParam+comlsqr.nInstrParam],dcopy,(int) comlsqr.nGlobalParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); -#pragma omp for - for(i=0;i<comlsqr.nGlobalParam;i++) + vVect[localAstroMax + comlsqr.nAttParam + i] = dcopy[i]; + } + free(dcopy); + dcopy = (double *)calloc(comlsqr.nGlobalParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + MPI_Allreduce(&vVect[localAstroMax + comlsqr.nAttParam + comlsqr.nInstrParam], dcopy, (int)comlsqr.nGlobalParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // FV EDIT + //#pragma omp for + for (i = 0; i < comlsqr.nGlobalParam; i++) { - vVect[localAstroMax+comlsqr.nAttParam+comlsqr.nInstrParam+i]=dcopy[i]; - } - free(dcopy); - if(nAstroPSolved) SumCirc(vVect,comlsqr); -#pragma omp for - for(i=0;i<localAstro;i++) + vVect[localAstroMax + comlsqr.nAttParam + comlsqr.nInstrParam + i] = dcopy[i]; + } + free(dcopy); + if (nAstroPSolved) + SumCirc(vVect, comlsqr); + // FV EDIT + //#pragma omp for + for (i = 0; i < localAstro; i++) { - vVect[i]+=vAuxVect[i]; - } - - - - - nAstroElements=comlsqr.mapStar[myid][1]-comlsqr.mapStar[myid][0] +1; - if(myid<nproc-1) - { - nAstroElements=comlsqr.mapStar[myid][1]-comlsqr.mapStar[myid][0] +1; - if(comlsqr.mapStar[myid][1]==comlsqr.mapStar[myid+1][0]) nAstroElements--; - } - - - double alphaLoc=0; - if(nAstroPSolved) alphaLoc=cblas_dnrm2(nAstroElements*comlsqr.nAstroPSolved,vVect,1); - double alphaLoc2=alphaLoc*alphaLoc; - if(myid==0) { - double alphaOther=cblas_dnrm2(comlsqr.nunkSplit-localAstroMax,&vVect[localAstroMax],1); - double alphaOther2=alphaOther*alphaOther; - alphaLoc2=alphaLoc2+alphaOther2; - } - double alphaGlob2=0; - MPI_Allreduce(&alphaLoc2, &alphaGlob2,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - alpha=sqrt(alphaGlob2); - - } - - if (alpha > ZERO) + vVect[i] += vAuxVect[i]; + } + + nAstroElements = comlsqr.mapStar[myid][1] - comlsqr.mapStar[myid][0] + 1; + if (myid < nproc - 1) { - cblas_dscal ( nunkSplit, (ONE / alpha), vVect, 1 ); - cblas_dcopy ( nunkSplit, vVect, 1, wVect, 1 ); + nAstroElements = comlsqr.mapStar[myid][1] - comlsqr.mapStar[myid][0] + 1; + if (comlsqr.mapStar[myid][1] == comlsqr.mapStar[myid + 1][0]) + nAstroElements--; } + + double alphaLoc = 0; + if (nAstroPSolved) + alphaLoc = cblas_dnrm2(nAstroElements * comlsqr.nAstroPSolved, vVect, 1); + double alphaLoc2 = alphaLoc * alphaLoc; + if (myid == 0) + { + double alphaOther = cblas_dnrm2(comlsqr.nunkSplit - localAstroMax, &vVect[localAstroMax], 1); + double alphaOther2 = alphaOther * alphaOther; + alphaLoc2 = alphaLoc2 + alphaOther2; + } + double alphaGlob2 = 0; + MPI_Allreduce(&alphaLoc2, &alphaGlob2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + alpha = sqrt(alphaGlob2); +} + +if (alpha > ZERO) +{ + cblas_dscal(nunkSplit, (ONE / alpha), vVect, 1); + cblas_dcopy(nunkSplit, vVect, 1, wVect, 1); +} // printf("LSQR T4: PE=%d alpha=%15.12lf beta=%15.12lf arnorm=%15.12lf\n",myid,alpha,beta,arnorm); - arnorm = alpha * beta; - arnorm0 = arnorm; +arnorm = alpha * beta; +arnorm0 = arnorm; // printf("LSQR T5: PE=%d alpha=%15.12lf beta=%15.12lf arnorm=%15.12lf\n",myid,alpha,beta,arnorm); - if (arnorm == ZERO) goto goto_800; - rhobar = alpha; - phibar = beta; - bnorm = beta; - rnorm = beta; +if (arnorm == ZERO) + goto goto_800; +rhobar = alpha; +phibar = beta; +bnorm = beta; +rnorm = beta; - if (myid==0) +if (myid == 0) +{ + nout = fopen(lsqrOut, "a"); + if (nout != NULL) { - nout=fopen(lsqrOut,"a"); - if ( nout != NULL) { - if ( damped ) - fprintf(nout, fmt_1300); - else - fprintf(nout, fmt_1200); - } else { - printf("Error while opening %s (2)\n",lsqrOut); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - - test1 = ONE; - test2 = alpha / beta; - - if ( extra ) - fprintf(nout, fmt_1400); - - fprintf(nout, fmt_1550, itn, xSolution[0], rnorm, test1, test2); - fprintf(nout, fmt_1600); - fclose(nout); + if (damped) + fprintf(nout, fmt_1300); + else + fprintf(nout, fmt_1200); } + else + { + printf("Error while opening %s (2)\n", lsqrOut); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + + test1 = ONE; + test2 = alpha / beta; + + if (extra) + fprintf(nout, fmt_1400); + + fprintf(nout, fmt_1550, itn, xSolution[0], rnorm, test1, test2); + fprintf(nout, fmt_1600); + fclose(nout); +} // ================================================================== // CheckPointRestart // ================================================================== - - if(!noCPR) - if(myid==0) printf("PE=%d call restart setup\n",myid); - restartSetup( &itn, - knownTerms, - &beta, - &alpha, - vVect, - &anorm, - &rhobar, - &phibar, - wVect, - xSolution, - standardError, - &dnorm, - &sn2, - &cs2, - &z, - &xnorm1, - &res2, - &nstop, - comlsqr); - if(myid==0) printf("PE=%d end restart setup\n",myid); + +if (!noCPR) + if (myid == 0) + printf("PE=%d call restart setup\n", myid); +restartSetup(&itn, + knownTerms, + &beta, + &alpha, + vVect, + &anorm, + &rhobar, + &phibar, + wVect, + xSolution, + standardError, + &dnorm, + &sn2, + &cs2, + &z, + &xnorm1, + &res2, + &nstop, + comlsqr); +if (myid == 0) + printf("PE=%d end restart setup\n", myid); // ================================================================== // Main iteration loop. // ================================================================== - if(myid==0) - { - startCycleTime=time(NULL); - } -//////////////////////// START ITERATIONS - while (1) { - writeCPR=0; // No write CPR - cycleStartMpiTime=MPI_Wtime(); - itnTest=-1; - if(myid==0){ - fpItnLimitNew=NULL; - fpItnLimitNew=fopen("ITNLIMIT_NEW","r"); - if (fpItnLimitNew!=NULL) - { - fscanf(fpItnLimitNew, "%d\n",&itnTest); - if(itnTest>0) +if (myid == 0) +{ + startCycleTime = time(NULL); +} +//////////////////////// START ITERATIONS +while (1) +{ + writeCPR = 0; // No write CPR + cycleStartMpiTime = MPI_Wtime(); + itnTest = -1; + if (myid == 0) + { + fpItnLimitNew = NULL; + fpItnLimitNew = fopen("ITNLIMIT_NEW", "r"); + if (fpItnLimitNew != NULL) + { + fscanf(fpItnLimitNew, "%d\n", &itnTest); + if (itnTest > 0) { - comlsqr.itnLimit=itnTest; - if(itnlim != itnTest){ - itnlim=itnTest; - if(myid==0) printf("itnLimit forced with ITNLIMIT_NEW file to value %d\n",itnlim); + comlsqr.itnLimit = itnTest; + if (itnlim != itnTest) + { + itnlim = itnTest; + if (myid == 0) + printf("itnLimit forced with ITNLIMIT_NEW file to value %d\n", itnlim); } } fclose(fpItnLimitNew); - } } - - if(myid==0) + } + + if (myid == 0) + { + endCycleTime = time(NULL) - startCycleTime; + startCycleTime = time(NULL); + totTime = totTime + endCycleTime; + partialTime = partialTime + endCycleTime; + if (!noCPR) { - endCycleTime=time(NULL)-startCycleTime; - startCycleTime=time(NULL); - totTime=totTime+endCycleTime; - partialTime=partialTime+endCycleTime; - if(!noCPR){ - - if(partialTime>comlsqr.timeCPR*60) - { - writeCPR=1; - partialTime=0; - } - if(totTime+endCycleTime*2>comlsqr.timeLimit*60) writeCPR=2; - - if(CPRCount>0 && CPRCount%comlsqr.itnCPR==0) writeCPR=1; - if(CPRCount>0 && CPRCount==comlsqr.itnCPRstop) writeCPR=2; - if(CPRCount==itnlim) writeCPR=2; - fpCPRend=NULL; - fpCPRend=fopen("CPR_END","r"); - if (fpCPRend!=NULL) + + if (partialTime > comlsqr.timeCPR * 60) { - itnTest=-1; - fscanf(fpCPRend, "%d\n",&itnTest); - if(itnTest>0) + writeCPR = 1; + partialTime = 0; + } + if (totTime + endCycleTime * 2 > comlsqr.timeLimit * 60) + writeCPR = 2; + + if (CPRCount > 0 && CPRCount % comlsqr.itnCPR == 0) + writeCPR = 1; + if (CPRCount > 0 && CPRCount == comlsqr.itnCPRstop) + writeCPR = 2; + if (CPRCount == itnlim) + writeCPR = 2; + fpCPRend = NULL; + fpCPRend = fopen("CPR_END", "r"); + if (fpCPRend != NULL) + { + itnTest = -1; + fscanf(fpCPRend, "%d\n", &itnTest); + if (itnTest > 0) { - if(comlsqr.itnCPRend != itnTest){ - comlsqr.itnCPRend=itnTest; - printf("itnCPRend forced with CPR_END file to value %d\n",comlsqr.itnCPRend); + if (comlsqr.itnCPRend != itnTest) + { + comlsqr.itnCPRend = itnTest; + printf("itnCPRend forced with CPR_END file to value %d\n", comlsqr.itnCPRend); } } fclose(fpCPRend); } - if(comlsqr.itnCPRend>0 && comlsqr.itnCPRend<=itn) + if (comlsqr.itnCPRend > 0 && comlsqr.itnCPRend <= itn) { - writeCPR=2; - printf("itnCPRend condition triggered to value %d. writeCPR set to 2.\n",comlsqr.itnCPRend); + writeCPR = 2; + printf("itnCPRend condition triggered to value %d. writeCPR set to 2.\n", comlsqr.itnCPRend); } - }//if(!noCPR) - }//if(myid==0) - MPI_Barrier(MPI_COMM_WORLD); - MPI_Bcast( &writeCPR, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &itnlim, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &comlsqr.itnLimit, 1, MPI_INT, 0, MPI_COMM_WORLD); - if(myid==0) - { - printf("lsqr: Iteration number %d. Iteration seconds %ld. OmpSec %d Global Seconds %ld \n",itn,endCycleTime,ompSec,totTime); - if(writeCPR==1) printf("... writing CPR files\n"); - if(writeCPR==2) printf("... writing CPR files and return\n"); - } - - - if(writeCPR>0) - { - if(myid==0) - CPRtimeStart=time(NULL); - writeCheckPoint(itn, - knownTerms, - beta, - alpha, - vVect, - anorm, - rhobar, - phibar, - wVect, - xSolution, - standardError, - dnorm, - sn2, - cs2, - z, - xnorm1, - res2, - nstop, - comlsqr); - - if(myid==0){ - CPRtimeEnd=time(NULL)-CPRtimeStart; - totTime+=CPRtimeEnd; - partialTime+=CPRtimeEnd; - printf("CPR: itn=%d writing CPR seconds %ld. Global Seconds %ld \n",itn,CPRtimeEnd, totTime); - } - - if(writeCPR==2) - { - *istop_out = 1000; - *itn_out = itn; - if(nAstroPSolved) free(vAuxVect); - return; - } - if(myid==0) startCycleTime=time(NULL); - } + } //if(!noCPR) + } //if(myid==0) + MPI_Barrier(MPI_COMM_WORLD); + MPI_Bcast(&writeCPR, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&itnlim, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&comlsqr.itnLimit, 1, MPI_INT, 0, MPI_COMM_WORLD); + if (myid == 0) + { + printf("lsqr: Iteration number %d. Iteration seconds %ld. OmpSec %d Global Seconds %ld \n", itn, endCycleTime, ompSec, totTime); + if (writeCPR == 1) + printf("... writing CPR files\n"); + if (writeCPR == 2) + printf("... writing CPR files and return\n"); + } - itn = itn + 1; - comlsqr.itn=itn; - CPRCount++; -// ------------------------------------------------------------------ -// Perform the next step of the bidiagonalization to obtain the -// next beta, u, alpha, v. These satisfy the relations -// beta*u = A*v - alpha*u, -// alpha*v = A(transpose)*u - beta*v. -// ------------------------------------------------------------------ - cblas_dscal ( mapNoss[myid]+nEqExtConstr+nEqBarConstr+nOfInstrConstr, (- alpha), knownTerms, 1 ); - kAuxcopy=(double *) calloc(nEqExtConstr+nEqBarConstr+nOfInstrConstr, sizeof(double)); - for (int kk=0;kk<nEqExtConstr+nEqBarConstr+nOfInstrConstr;kk++){ - kAuxcopy[kk]=knownTerms[mapNoss[myid]+kk]; - knownTerms[mapNoss[myid]+kk]=0.; + if (writeCPR > 0) + { + if (myid == 0) + CPRtimeStart = time(NULL); + writeCheckPoint(itn, + knownTerms, + beta, + alpha, + vVect, + anorm, + rhobar, + phibar, + wVect, + xSolution, + standardError, + dnorm, + sn2, + cs2, + z, + xnorm1, + res2, + nstop, + comlsqr); + + if (myid == 0) + { + CPRtimeEnd = time(NULL) - CPRtimeStart; + totTime += CPRtimeEnd; + partialTime += CPRtimeEnd; + printf("CPR: itn=%d writing CPR seconds %ld. Global Seconds %ld \n", itn, CPRtimeEnd, totTime); } - aprod ( 1, m, n, vVect, knownTerms, systemMatrix, matrixIndex, instrCol,instrConstrIlung, comlsqr,&ompSec ); - kcopy=(double *) calloc(nEqExtConstr+nEqBarConstr+nOfInstrConstr, sizeof(double)); - MPI_Allreduce(&knownTerms[mapNoss[myid]],kcopy,nEqExtConstr+nEqBarConstr+nOfInstrConstr,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - for(i=0;i<nEqExtConstr+nEqBarConstr+nOfInstrConstr;i++) + + if (writeCPR == 2) { - knownTerms[mapNoss[myid]+i]=kcopy[i]+kAuxcopy[i]; + *istop_out = 1000; + *itn_out = itn; + if (nAstroPSolved) + free(vAuxVect); + return; } - free(kAuxcopy); - free(kcopy); -// beta = cblas_dnrm2 ( m, u, 1 ); + if (myid == 0) + startCycleTime = time(NULL); + } + + itn = itn + 1; + comlsqr.itn = itn; + CPRCount++; + // ------------------------------------------------------------------ + // Perform the next step of the bidiagonalization to obtain the + // next beta, u, alpha, v. These satisfy the relations + // beta*u = A*v - alpha*u, + // alpha*v = A(transpose)*u - beta*v. + // ------------------------------------------------------------------ + cblas_dscal(mapNoss[myid] + nEqExtConstr + nEqBarConstr + nOfInstrConstr, (-alpha), knownTerms, 1); + kAuxcopy = (double *)calloc(nEqExtConstr + nEqBarConstr + nOfInstrConstr, sizeof(double)); + for (int kk = 0; kk < nEqExtConstr + nEqBarConstr + nOfInstrConstr; kk++) + { + kAuxcopy[kk] = knownTerms[mapNoss[myid] + kk]; + knownTerms[mapNoss[myid] + kk] = 0.; + } + + aprod(1, m, n, vVect, knownTerms, systemMatrix, matrixIndex, instrCol, instrConstrIlung, comlsqr, &ompSec); - if(myid==0) betaLoc=cblas_dnrm2(mapNoss[myid]+nEqExtConstr+nEqBarConstr+nOfInstrConstr,knownTerms,1); - else betaLoc=cblas_dnrm2(mapNoss[myid],knownTerms,1); - betaLoc2=betaLoc*betaLoc; - MPI_Allreduce(&betaLoc2, &betaGlob,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - beta=sqrt(betaGlob); -// printf("LSQR TP8 PE=%d itn=%d: alpha=%15.12lf beta=%15.12lf\n",myid,itn,alpha,beta); + + + + + + kcopy = (double *)calloc(nEqExtConstr + nEqBarConstr + nOfInstrConstr, sizeof(double)); + MPI_Allreduce(&knownTerms[mapNoss[myid]], kcopy, nEqExtConstr + nEqBarConstr + nOfInstrConstr, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + for (i = 0; i < nEqExtConstr + nEqBarConstr + nOfInstrConstr; i++) + { + knownTerms[mapNoss[myid] + i] = kcopy[i] + kAuxcopy[i]; + } + free(kAuxcopy); + free(kcopy); + // beta = cblas_dnrm2 ( m, u, 1 ); + if (myid == 0) + betaLoc = cblas_dnrm2(mapNoss[myid] + nEqExtConstr + nEqBarConstr + nOfInstrConstr, knownTerms, 1); + else + betaLoc = cblas_dnrm2(mapNoss[myid], knownTerms, 1); + betaLoc2 = betaLoc * betaLoc; + MPI_Allreduce(&betaLoc2, &betaGlob, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + beta = sqrt(betaGlob); -// Accumulate anorm = || Bk || -// = sqrt( sum of alpha**2 + beta**2 + damp**2 ). + // printf("LSQR TP8 PE=%d itn=%d: alpha=%15.12lf beta=%15.12lf\n",myid,itn,alpha,beta); - temp = d2norm( alpha, beta ); - temp = d2norm( temp , damp ); - anorm = d2norm( anorm, temp ); + // Accumulate anorm = || Bk || + // = sqrt( sum of alpha**2 + beta**2 + damp**2 ). - if (beta > ZERO) { - cblas_dscal ( mapNoss[myid]+nEqExtConstr+nEqBarConstr+nOfInstrConstr, (ONE / beta), knownTerms, 1 ); - cblas_dscal ( nunkSplit, (- beta), vVect, 1 ); -//only processor 0 accumulate and distribute the v array -#pragma omp for - for(i=0;i<localAstroMax;i++) { - vAuxVect[i]=vVect[i]; - vVect[i]=0; - } - if(myid!=0) - { -#pragma omp for - for(i=localAstroMax;i<nunkSplit;i++) - vVect[i]=0; - } - - aprod ( 2, m, n, vVect, knownTerms, systemMatrix, matrixIndex, instrCol, instrConstrIlung, comlsqr,&ompSec); - MPI_Barrier(MPI_COMM_WORLD); - - -//////////////// TEST vVect -/* -if(nproc==2) -{ - printf("LSQR TP9 PE=%d itn=%d VrIdAstroPDim=%ld vVect[0-5]=%lf %lf %lf %lf %lf VrIdAstroPDim/2*5=%ld vVect[..+4]=%lf %lf %lf %lf %lf VrIdAstroPDim-1*5=%ld vVect[...+5]=%lf %lf %lf %lf %lf\n",myid,itn,VrIdAstroPDim,vVect[0],vVect[1],vVect[2],vVect[3],vVect[4],(VrIdAstroPDim/2)*5,vVect[(VrIdAstroPDim/2)*5],vVect[(VrIdAstroPDim/2)*5+1],vVect[(VrIdAstroPDim/2)*5+2],vVect[(VrIdAstroPDim/2)*5+3],vVect[(VrIdAstroPDim/2)*5+4],(VrIdAstroPDim-1)*5,vVect[(VrIdAstroPDim-1)*5],vVect[(VrIdAstroPDim-1)*5+1],vVect[(VrIdAstroPDim-1)*5+2],vVect[(VrIdAstroPDim-1)*5+3],vVect[(VrIdAstroPDim-1)*5+4]); -} -if(nproc==1) -{ - printf("LSQR TP9 PE=%d itn=%d VrIdAstroPDim=%ld vVect[0-5]=%lf %lf %lf %lf %lf VrIdAstroPDim/2*5=%ld vVect[..+4]=%lf %lf %lf %lf %lf VrIdAstroPDim-1*5=%ld vVect[...+5]=%lf %lf %lf %lf %lf\n",myid,itn,VrIdAstroPDim,vVect[0],vVect[1],vVect[2],vVect[3],vVect[4],(VrIdAstroPDim/2)*5,vVect[(VrIdAstroPDim/2)*5],vVect[(VrIdAstroPDim/2)*5+1],vVect[(VrIdAstroPDim/2)*5+2],vVect[(VrIdAstroPDim/2)*5+3],vVect[(VrIdAstroPDim/2)*5+4],(VrIdAstroPDim-1)*5,vVect[(VrIdAstroPDim-1)*5],vVect[(VrIdAstroPDim-1)*5+1],vVect[(VrIdAstroPDim-1)*5+2],vVect[(VrIdAstroPDim-1)*5+3],vVect[(VrIdAstroPDim-1)*5+4]); -} -*/ -////////////////////////// - + temp = d2norm(alpha, beta); + temp = d2norm(temp, damp); + anorm = d2norm(anorm, temp); - double *dcopy; - dcopy=(double *)calloc(comlsqr.nAttParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - mpi_allreduce(&vVect[localAstroMax],dcopy,(long int) comlsqr.nAttParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); -#pragma omp for - for(i=0;i<comlsqr.nAttParam;i++) - { - vVect[localAstroMax+i]=dcopy[i]; - } - free(dcopy); - dcopy=(double *)calloc(comlsqr.nInstrParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - mpi_allreduce(&vVect[localAstroMax+comlsqr.nAttParam],dcopy,(long int) comlsqr.nInstrParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); -#pragma omp for - for(i=0;i<comlsqr.nInstrParam;i++) + if (beta > ZERO) { - vVect[localAstroMax+comlsqr.nAttParam+i]=dcopy[i]; - } - free(dcopy); - dcopy=(double *)calloc(comlsqr.nGlobalParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - mpi_allreduce(&vVect[localAstroMax+comlsqr.nAttParam+comlsqr.nInstrParam],dcopy,(long int) comlsqr.nGlobalParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - for(i=0;i<comlsqr.nGlobalParam;i++) - { - vVect[localAstroMax+comlsqr.nAttParam+comlsqr.nInstrParam+i]=dcopy[i]; - } - free(dcopy); - if(nAstroPSolved) SumCirc(vVect,comlsqr); -#pragma omp for - for(i=0;i<localAstroMax;i++) { - vVect[i]+=vAuxVect[i]; - } - - double alphaLoc=0; - if(nAstroPSolved) alphaLoc=cblas_dnrm2(nAstroElements*comlsqr.nAstroPSolved,vVect,1); - double alphaLoc2=alphaLoc*alphaLoc; - if(myid==0) { - double alphaOther=cblas_dnrm2(comlsqr.nunkSplit-localAstroMax,&vVect[localAstroMax],1); - double alphaOther2=alphaOther*alphaOther; - alphaLoc2=alphaLoc2+alphaOther2; - } - double alphaGlob2=0; - MPI_Allreduce(&alphaLoc2, &alphaGlob2,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - - alpha=sqrt(alphaGlob2); - if (alpha > ZERO) { - cblas_dscal ( nunkSplit, (ONE / alpha), vVect, 1 ); - } + cblas_dscal(mapNoss[myid] + nEqExtConstr + nEqBarConstr + nOfInstrConstr, (ONE / beta), knownTerms, 1); + cblas_dscal(nunkSplit, (-beta), vVect, 1); +//only processor 0 accumulate and distribute the v array + // FV EDIT + //#pragma omp for + for (i = 0; i < localAstroMax; i++) + { + vAuxVect[i] = vVect[i]; + vVect[i] = 0; } - -// ------------------------------------------------------------------ -// Use a plane rotation to eliminate the damping parameter. -// This alters the diagonal (rhobar) of the lower-bidiagonal matrix. -// ------------------------------------------------------------------ - rhbar1 = rhobar; - if ( damped ) { - rhbar1 = d2norm( rhobar, damp ); - cs1 = rhobar / rhbar1; - sn1 = damp / rhbar1; - psi = sn1 * phibar; - phibar = cs1 * phibar; + if (myid != 0) + { + // FV EDIT + //#pragma omp for + for (i = localAstroMax; i < nunkSplit; i++) + vVect[i] = 0; } -// ------------------------------------------------------------------ -// Use a plane rotation to eliminate the subdiagonal element (beta) -// of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix. -// ------------------------------------------------------------------ - rho = d2norm( rhbar1, beta ); - cs = rhbar1 / rho; - sn = beta / rho; - theta = sn * alpha; - rhobar = - cs * alpha; - phi = cs * phibar; - phibar = sn * phibar; - tau = sn * phi; - -// ------------------------------------------------------------------ -// Update x, w and (perhaps) the standard error estimates. -// ------------------------------------------------------------------ - t1 = phi / rho; - t2 = - theta / rho; - t3 = ONE / rho; - dknorm = ZERO; - - for (i = 0; i < nAstroElements*comlsqr.nAstroPSolved; i++) { - t = wVect[i]; - t = (t3*t)*(t3*t); - dknorm = t + dknorm; + aprod(2, m, n, vVect, knownTerms, systemMatrix, matrixIndex, instrCol, instrConstrIlung, comlsqr, &ompSec ); + MPI_Barrier(MPI_COMM_WORLD); + //MPI_Finalize(); + //exit(0); + + //////////////// TEST vVect + /* + if(nproc==2) + { + printf("LSQR TP9 PE=%d itn=%d VrIdAstroPDim=%ld vVect[0-5]=%lf %lf %lf %lf %lf VrIdAstroPDim/2*5=%ld vVect[..+4]=%lf %lf %lf %lf %lf VrIdAstroPDim-1*5=%ld vVect[...+5]=%lf %lf %lf %lf %lf\n",myid,itn,VrIdAstroPDim,vVect[0],vVect[1],vVect[2],vVect[3],vVect[4],(VrIdAstroPDim/2)*5,vVect[(VrIdAstroPDim/2)*5],vVect[(VrIdAstroPDim/2)*5+1],vVect[(VrIdAstroPDim/2)*5+2],vVect[(VrIdAstroPDim/2)*5+3],vVect[(VrIdAstroPDim/2)*5+4],(VrIdAstroPDim-1)*5,vVect[(VrIdAstroPDim-1)*5],vVect[(VrIdAstroPDim-1)*5+1],vVect[(VrIdAstroPDim-1)*5+2],vVect[(VrIdAstroPDim-1)*5+3],vVect[(VrIdAstroPDim-1)*5+4]); } - dknormSum=0; - MPI_Allreduce(&dknorm,&dknormSum,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - dknorm=dknormSum; - - if ( wantse ) { -#pragma omp for - for (i = 0; i < localAstro; i++) { - t = wVect[i]; - xSolution[i] = t1*t + xSolution[i]; - wVect[i] = t2*t + vVect[i]; - t = (t3*t)*(t3*t); - standardError[i] = t + standardError[i]; - } -#pragma omp for - for (i = localAstroMax; i < localAstroMax+other; i++) { - t = wVect[i]; - xSolution[i] = t1*t + xSolution[i]; - wVect[i] = t2*t + vVect[i]; - t = (t3*t)*(t3*t); - standardError[i] = t + standardError[i]; - } - for (i = localAstroMax; i < localAstroMax+other; i++) { - t = wVect[i]; - t = (t3*t)*(t3*t); - dknorm = t + dknorm; - } + if(nproc==1) + { + printf("LSQR TP9 PE=%d itn=%d VrIdAstroPDim=%ld vVect[0-5]=%lf %lf %lf %lf %lf VrIdAstroPDim/2*5=%ld vVect[..+4]=%lf %lf %lf %lf %lf VrIdAstroPDim-1*5=%ld vVect[...+5]=%lf %lf %lf %lf %lf\n",myid,itn,VrIdAstroPDim,vVect[0],vVect[1],vVect[2],vVect[3],vVect[4],(VrIdAstroPDim/2)*5,vVect[(VrIdAstroPDim/2)*5],vVect[(VrIdAstroPDim/2)*5+1],vVect[(VrIdAstroPDim/2)*5+2],vVect[(VrIdAstroPDim/2)*5+3],vVect[(VrIdAstroPDim/2)*5+4],(VrIdAstroPDim-1)*5,vVect[(VrIdAstroPDim-1)*5],vVect[(VrIdAstroPDim-1)*5+1],vVect[(VrIdAstroPDim-1)*5+2],vVect[(VrIdAstroPDim-1)*5+3],vVect[(VrIdAstroPDim-1)*5+4]); } - else { -#pragma omp for - for (i = 0; i < localAstro; i++) { - t = wVect[i]; - xSolution[i] = t1*t + xSolution[i]; - wVect[i] = t2*t + vVect[i]; - } -#pragma omp for - for (i = localAstroMax; i < localAstroMax+other; i++) { - t = wVect[i]; - xSolution[i] = t1*t + xSolution[i]; - wVect[i] = t2*t + vVect[i]; - } - for (i = localAstroMax; i < localAstroMax+other; i++) { - t = wVect[i]; - dknorm = (t3*t)*(t3*t) + dknorm; - } + */ + ////////////////////////// + + double *dcopy; + dcopy = (double *)calloc(comlsqr.nAttParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + mpi_allreduce(&vVect[localAstroMax], dcopy, (long int)comlsqr.nAttParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // FV EDIT + //#pragma omp for + for (i = 0; i < comlsqr.nAttParam; i++) + { + vVect[localAstroMax + i] = dcopy[i]; + } + free(dcopy); + dcopy = (double *)calloc(comlsqr.nInstrParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + mpi_allreduce(&vVect[localAstroMax + comlsqr.nAttParam], dcopy, (long int)comlsqr.nInstrParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // FV EDIT + //#pragma omp for + for (i = 0; i < comlsqr.nInstrParam; i++) + { + vVect[localAstroMax + comlsqr.nAttParam + i] = dcopy[i]; + } + free(dcopy); + dcopy = (double *)calloc(comlsqr.nGlobalParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + mpi_allreduce(&vVect[localAstroMax + comlsqr.nAttParam + comlsqr.nInstrParam], dcopy, (long int)comlsqr.nGlobalParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + for (i = 0; i < comlsqr.nGlobalParam; i++) + { + vVect[localAstroMax + comlsqr.nAttParam + comlsqr.nInstrParam + i] = dcopy[i]; + } + free(dcopy); + if (nAstroPSolved) + SumCirc(vVect, comlsqr); + // FV EDIT + //#pragma omp for + for (i = 0; i < localAstroMax; i++) + { + vVect[i] += vAuxVect[i]; } -// ------------------------------------------------------------------ -// Monitor the norm of d_k, the update to x. -// dknorm = norm( d_k ) -// dnorm = norm( D_k ), where D_k = (d_1, d_2, ..., d_k ) -// dxk = norm( phi_k d_k ), where new x = x_k + phi_k d_k. -// ------------------------------------------------------------------ - dknorm = sqrt( dknorm ); - dnorm = d2norm( dnorm, dknorm ); - dxk = fabs( phi * dknorm ); - if (dxmax < dxk ) { - dxmax = dxk; - maxdx = itn; + double alphaLoc = 0; + if (nAstroPSolved) + alphaLoc = cblas_dnrm2(nAstroElements * comlsqr.nAstroPSolved, vVect, 1); + double alphaLoc2 = alphaLoc * alphaLoc; + if (myid == 0) + { + double alphaOther = cblas_dnrm2(comlsqr.nunkSplit - localAstroMax, &vVect[localAstroMax], 1); + double alphaOther2 = alphaOther * alphaOther; + alphaLoc2 = alphaLoc2 + alphaOther2; } + double alphaGlob2 = 0; + MPI_Allreduce(&alphaLoc2, &alphaGlob2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -// ------------------------------------------------------------------ -// Use a plane rotation on the right to eliminate the -// super-diagonal element (theta) of the upper-bidiagonal matrix. -// Then use the result to estimate norm(x). -// ------------------------------------------------------------------ - delta = sn2 * rho; - gambar = - cs2 * rho; - rhs = phi - delta * z; - zbar = rhs / gambar; - xnorm = d2norm( xnorm1, zbar ); - gamma = d2norm( gambar, theta ); - cs2 = gambar / gamma; - sn2 = theta / gamma; - z = rhs / gamma; - xnorm1 = d2norm( xnorm1, z ); - -// ------------------------------------------------------------------ -// Test for convergence. -// First, estimate the norm and condition of the matrix Abar, -// and the norms of rbar and Abar(transpose)*rbar. -// ------------------------------------------------------------------ - acond = anorm * dnorm; - res2 = d2norm( res2 , psi ); - rnorm = d2norm( res2 , phibar ); - arnorm = alpha * fabs( tau ); - -// Now use these norms to estimate certain other quantities, -// some of which will be small near a solution. - - alfopt = sqrt( rnorm / (dnorm * xnorm) ); - test1 = rnorm / bnorm; - test2 = ZERO; - if (rnorm > ZERO) test2 = arnorm / (anorm * rnorm); -// if (arnorm0 > ZERO) test2 = arnorm / arnorm0; //(Michael Friedlander's modification) - test3 = ONE / acond; - t1 = test1 / (ONE + anorm * xnorm / bnorm); - rtol = btol + atol * anorm * xnorm / bnorm; - -// The following tests guard against extremely small values of -// atol, btol or ctol. (The user may have set any or all of -// the parameters atol, btol, conlim to zero.) -// The effect is equivalent to the normal tests using -// atol = relpr, btol = relpr, conlim = 1/relpr. - - t3 = ONE + test3; - t2 = ONE + test2; - t1 = ONE + t1; -// printf("LSQR TP8 PE=%d itn=%d test1=%18.16lf, rnorm=%lf bnorm=%lf anorm=%lf xnorm=%lf rtol=%lf t1=%18.16lf\n",myid,itn,test1,rnorm,bnorm,anorm,xnorm,rtol,t1); - - if (itn >= itnlim) istop = 5; - if (t3 <= ONE ) istop = 4; - if (t2 <= ONE ) istop = 2; - if (t1 <= ONE ) istop = 1; -// if (t1 <= ONE ) printf("PE=%d t1=%lf\n",myid,t1); - -// Allow for tolerances set by the user. - - if (test3 <= ctol) istop = 4; - if (test2 <= atol) istop = 2; - if (test1 <= rtol) istop = 1; //(Michael Friedlander had this commented out) -// if (test1 <= rtol) printf("PE=%d test1=%lf\n",myid,test1); - -// ------------------------------------------------------------------ -// See if it is time to print something. -// ------------------------------------------------------------------ -// if (nout == NULL ) goto goto_600; // Delete for buffer flush modification??? TBV - if (n <= 40 ) goto goto_400; - if (itn <= 10 ) goto goto_400; - if (itn >= itnlim-10) goto goto_400; - if (itn % 10 == 0 ) goto goto_400; - if (test3 <= 2.0*ctol) goto goto_400; - if (test2 <= 10.0*atol) goto goto_400; - if (test1 <= 10.0*rtol) goto goto_400; - if (istop != 0 ) goto goto_400; - goto goto_600; - -// Print a line for this iteration. -// "extra" is for experimental purposes. - - goto_400: - if(!comlsqr.Test) - if(myid==0) { - nout=fopen(lsqrOut,"a"); - if ( nout != NULL) { - if ( extra ) { - fprintf(nout, fmt_1500_extra, - itn, xSolution[0], rnorm, test1, test2, anorm, - acond, phi, dknorm, dxk, alfopt); - } else { - fprintf(nout, fmt_1500, - itn, xSolution[0], rnorm, test1, test2, anorm, acond); - } - if (itn % 10 == 0) fprintf(nout, fmt_1600); - } else { - printf("Error while opening %s (3)\n",lsqrOut); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - fclose(nout); + alpha = sqrt(alphaGlob2); + if (alpha > ZERO) + { + cblas_dscal(nunkSplit, (ONE / alpha), vVect, 1); } -// ------------------------------------------------------------------ -// Stop if appropriate. -// The convergence criteria are required to be met on nconv -// consecutive iterations, where nconv is set below. -// Suggested value: nconv = 1, 2 or 3. -// ------------------------------------------------------------------ - goto_600: - if (istop == 0) { - nstop = 0; + } + + // ------------------------------------------------------------------ + // Use a plane rotation to eliminate the damping parameter. + // This alters the diagonal (rhobar) of the lower-bidiagonal matrix. + // ------------------------------------------------------------------ + rhbar1 = rhobar; + if (damped) + { + rhbar1 = d2norm(rhobar, damp); + cs1 = rhobar / rhbar1; + sn1 = damp / rhbar1; + psi = sn1 * phibar; + phibar = cs1 * phibar; + } + + // ------------------------------------------------------------------ + // Use a plane rotation to eliminate the subdiagonal element (beta) + // of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix. + // ------------------------------------------------------------------ + rho = d2norm(rhbar1, beta); + cs = rhbar1 / rho; + sn = beta / rho; + theta = sn * alpha; + rhobar = -cs * alpha; + phi = cs * phibar; + phibar = sn * phibar; + tau = sn * phi; + + // ------------------------------------------------------------------ + // Update x, w and (perhaps) the standard error estimates. + // ------------------------------------------------------------------ + t1 = phi / rho; + t2 = -theta / rho; + t3 = ONE / rho; + dknorm = ZERO; + + for (i = 0; i < nAstroElements * comlsqr.nAstroPSolved; i++) + { + t = wVect[i]; + t = (t3 * t) * (t3 * t); + dknorm = t + dknorm; + } + dknormSum = 0; + MPI_Allreduce(&dknorm, &dknormSum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + dknorm = dknormSum; + + if (wantse) + { + // FV EDIT + //#pragma omp for + for (i = 0; i < localAstro; i++) + { + t = wVect[i]; + xSolution[i] = t1 * t + xSolution[i]; + wVect[i] = t2 * t + vVect[i]; + t = (t3 * t) * (t3 * t); + standardError[i] = t + standardError[i]; } - else { - nconv = 1; - nstop = nstop + 1; - if (nstop < nconv && itn < itnlim) istop = 0; + // FV EDIT + //#pragma omp for + for (i = localAstroMax; i < localAstroMax + other; i++) + { + t = wVect[i]; + xSolution[i] = t1 * t + xSolution[i]; + wVect[i] = t2 * t + vVect[i]; + t = (t3 * t) * (t3 * t); + standardError[i] = t + standardError[i]; } - - if(comlsqr.Test) + for (i = localAstroMax; i < localAstroMax + other; i++) { - if(itn<comlsqr.itnLimit) istop=0; - else (istop=5); - } - cycleEndMpiTime=MPI_Wtime(); -// printf("lsqr: PE=%d MPI-iteration number %d. Iteration seconds %f\n",myid,itn,cycleEndMpiTime-cycleStartMpiTime); + t = wVect[i]; + t = (t3 * t) * (t3 * t); + dknorm = t + dknorm; + } + } + else + { + // FV EDIT + //#pragma omp for + for (i = 0; i < localAstro; i++) + { + t = wVect[i]; + xSolution[i] = t1 * t + xSolution[i]; + wVect[i] = t2 * t + vVect[i]; + } + // FV EDIT + //#pragma omp for + for (i = localAstroMax; i < localAstroMax + other; i++) + { + t = wVect[i]; + xSolution[i] = t1 * t + xSolution[i]; + wVect[i] = t2 * t + vVect[i]; + } + for (i = localAstroMax; i < localAstroMax + other; i++) + { + t = wVect[i]; + dknorm = (t3 * t) * (t3 * t) + dknorm; + } + } - if (istop != 0) break; - + // ------------------------------------------------------------------ + // Monitor the norm of d_k, the update to x. + // dknorm = norm( d_k ) + // dnorm = norm( D_k ), where D_k = (d_1, d_2, ..., d_k ) + // dxk = norm( phi_k d_k ), where new x = x_k + phi_k d_k. + // ------------------------------------------------------------------ + dknorm = sqrt(dknorm); + dnorm = d2norm(dnorm, dknorm); + dxk = fabs(phi * dknorm); + if (dxmax < dxk) + { + dxmax = dxk; + maxdx = itn; } + + // ------------------------------------------------------------------ + // Use a plane rotation on the right to eliminate the + // super-diagonal element (theta) of the upper-bidiagonal matrix. + // Then use the result to estimate norm(x). + // ------------------------------------------------------------------ + delta = sn2 * rho; + gambar = -cs2 * rho; + rhs = phi - delta * z; + zbar = rhs / gambar; + xnorm = d2norm(xnorm1, zbar); + gamma = d2norm(gambar, theta); + cs2 = gambar / gamma; + sn2 = theta / gamma; + z = rhs / gamma; + xnorm1 = d2norm(xnorm1, z); + + // ------------------------------------------------------------------ + // Test for convergence. + // First, estimate the norm and condition of the matrix Abar, + // and the norms of rbar and Abar(transpose)*rbar. + // ------------------------------------------------------------------ + acond = anorm * dnorm; + res2 = d2norm(res2, psi); + rnorm = d2norm(res2, phibar); + arnorm = alpha * fabs(tau); + + // Now use these norms to estimate certain other quantities, + // some of which will be small near a solution. + + alfopt = sqrt(rnorm / (dnorm * xnorm)); + test1 = rnorm / bnorm; + test2 = ZERO; + if (rnorm > ZERO) + test2 = arnorm / (anorm * rnorm); + // if (arnorm0 > ZERO) test2 = arnorm / arnorm0; //(Michael Friedlander's modification) + test3 = ONE / acond; + t1 = test1 / (ONE + anorm * xnorm / bnorm); + rtol = btol + atol * anorm * xnorm / bnorm; + + // The following tests guard against extremely small values of + // atol, btol or ctol. (The user may have set any or all of + // the parameters atol, btol, conlim to zero.) + // The effect is equivalent to the normal tests using + // atol = relpr, btol = relpr, conlim = 1/relpr. + + t3 = ONE + test3; + t2 = ONE + test2; + t1 = ONE + t1; + // printf("LSQR TP8 PE=%d itn=%d test1=%18.16lf, rnorm=%lf bnorm=%lf anorm=%lf xnorm=%lf rtol=%lf t1=%18.16lf\n",myid,itn,test1,rnorm,bnorm,anorm,xnorm,rtol,t1); + + if (itn >= itnlim) + istop = 5; + if (t3 <= ONE) + istop = 4; + if (t2 <= ONE) + istop = 2; + if (t1 <= ONE) + istop = 1; + // if (t1 <= ONE ) printf("PE=%d t1=%lf\n",myid,t1); + + // Allow for tolerances set by the user. + + if (test3 <= ctol) + istop = 4; + if (test2 <= atol) + istop = 2; + if (test1 <= rtol) + istop = 1; //(Michael Friedlander had this commented out) + // if (test1 <= rtol) printf("PE=%d test1=%lf\n",myid,test1); + + // ------------------------------------------------------------------ + // See if it is time to print something. + // ------------------------------------------------------------------ + // if (nout == NULL ) goto goto_600; // Delete for buffer flush modification??? TBV + if (n <= 40) + goto goto_400; + if (itn <= 10) + goto goto_400; + if (itn >= itnlim - 10) + goto goto_400; + if (itn % 10 == 0) + goto goto_400; + if (test3 <= 2.0 * ctol) + goto goto_400; + if (test2 <= 10.0 * atol) + goto goto_400; + if (test1 <= 10.0 * rtol) + goto goto_400; + if (istop != 0) + goto goto_400; + goto goto_600; + + // Print a line for this iteration. + // "extra" is for experimental purposes. + +goto_400: + if (!comlsqr.Test) + if (myid == 0) + { + nout = fopen(lsqrOut, "a"); + if (nout != NULL) + { + if (extra) + { + fprintf(nout, fmt_1500_extra, + itn, xSolution[0], rnorm, test1, test2, anorm, + acond, phi, dknorm, dxk, alfopt); + } + else + { + fprintf(nout, fmt_1500, + itn, xSolution[0], rnorm, test1, test2, anorm, acond); + } + if (itn % 10 == 0) + fprintf(nout, fmt_1600); + } + else + { + printf("Error while opening %s (3)\n", lsqrOut); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + fclose(nout); + } + // ------------------------------------------------------------------ + // Stop if appropriate. + // The convergence criteria are required to be met on nconv + // consecutive iterations, where nconv is set below. + // Suggested value: nconv = 1, 2 or 3. + // ------------------------------------------------------------------ +goto_600: + if (istop == 0) + { + nstop = 0; + } + else + { + nconv = 1; + nstop = nstop + 1; + if (nstop < nconv && itn < itnlim) + istop = 0; + } + + if (comlsqr.Test) + { + if (itn < comlsqr.itnLimit) + istop = 0; + else + (istop = 5); + } + cycleEndMpiTime = MPI_Wtime(); + // printf("lsqr: PE=%d MPI-iteration number %d. Iteration seconds %f\n",myid,itn,cycleEndMpiTime-cycleStartMpiTime); + + if (istop != 0) + break; +} // ================================================================== // End of iteration loop. // ================================================================== // Finish off the standard error estimates. - if ( wantse ) { - t = ONE; - if (m > n) t = m - n; - if ( damped ) t = m; - t = rnorm / sqrt( t ); - - for (i = 0; i < nunkSplit; i++) - standardError[i] = t * sqrt( standardError[i] ); - - } +if (wantse) +{ + t = ONE; + if (m > n) + t = m - n; + if (damped) + t = m; + t = rnorm / sqrt(t); + + for (i = 0; i < nunkSplit; i++) + standardError[i] = t * sqrt(standardError[i]); +} // Decide if istop = 2 or 3. // Print the stopping condition. - goto_800: - if (damped && istop == 2) istop = 3; - if (myid == 0) { - nout=fopen(lsqrOut,"a"); - if (nout != NULL) { - fprintf(nout, fmt_2000, - exitLsqr, istop, itn, - exitLsqr, anorm, acond, - exitLsqr, bnorm, xnorm, - exitLsqr, rnorm, arnorm); - fprintf(nout, fmt_2100, - exitLsqr, dxmax, maxdx, - exitLsqr, dxmax/(xnorm + 1.0e-20)); - fprintf(nout, fmt_3000, - exitLsqr, msg[istop]); - } else { - printf("Error while opening %s (4)\n",lsqrOut); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - fclose(nout); - } +goto_800 : if (damped && istop == 2) istop = 3; +if (myid == 0) +{ + nout = fopen(lsqrOut, "a"); + if (nout != NULL) + { + fprintf(nout, fmt_2000, + exitLsqr, istop, itn, + exitLsqr, anorm, acond, + exitLsqr, bnorm, xnorm, + exitLsqr, rnorm, arnorm); + fprintf(nout, fmt_2100, + exitLsqr, dxmax, maxdx, + exitLsqr, dxmax / (xnorm + 1.0e-20)); + fprintf(nout, fmt_3000, + exitLsqr, msg[istop]); + } + else + { + printf("Error while opening %s (4)\n", lsqrOut); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + fclose(nout); +} // Assign output variables from local copies. - *istop_out = istop; - *itn_out = itn; - *anorm_out = anorm; - *acond_out = acond; - *rnorm_out = rnorm; - *arnorm_out = test2; - *xnorm_out = xnorm; - - if(nAstroPSolved) free(vAuxVect); - return; +*istop_out = istop; +*itn_out = itn; +*anorm_out = anorm; +*acond_out = acond; +*rnorm_out = rnorm; +*arnorm_out = test2; +*xnorm_out = xnorm; + +if (nAstroPSolved) + free(vAuxVect); +return; } - - diff --git a/lsqrblas.c b/lsqrblas.c index 7025ed1..1f3f715 100644 --- a/lsqrblas.c +++ b/lsqrblas.c @@ -26,6 +26,10 @@ */ #include <stdio.h> #include <stdlib.h> +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + + /*! \file @@ -95,7 +99,7 @@ cblas_daxpy( const int N, const double alpha, const double *X, */ void cblas_dcopy( const long int N, const double *X, - const int incX, double *Y, const int incY) + const int incX, double *Y, const int incY, int ntasks) { long int i,ix,iy; // int ix = OFFSET(N, incX); @@ -107,17 +111,24 @@ cblas_dcopy( const long int N, const double *X, else iy=((N) - 1) * (-(incY)); -#pragma omp parallel shared(ix, iy) +//#pragma omp parallel shared(ix, iy) +//#pragma omp task shared(ix, iy) { + + long ixThread,iyThread; long ixThreadOffset=ix, iyThreadOffset=iy; -#pragma omp for +//#pragma omp for for (i = 0; i < N; i++) { + //printf("Inside task %d\n", i); ixThread=ixThreadOffset+incX*i; iyThread=iyThreadOffset+incY*i; Y[iyThread] = X[ixThread]; } + + }//end pragma +//#pragma omp taskwait } /*! @@ -157,7 +168,7 @@ cblas_ddot( const int N, const double *X, */ double -cblas_dnrm2( const long int N, const double *X, const int incX) +cblas_dnrm2( const long int N, const double *X, const int incX, int ntasks) { double scale = 0.0, @@ -190,9 +201,9 @@ cblas_dnrm2( const long int N, const double *X, const int incX) return scale * sqrt(ssq); } - +//FV_ not used ?? double -cblas_dnrm21( const long int N, const double *X, const int incX) +cblas_dnrm21( const long int N, const double *X, const int incX, int ntasks=0) { double ssq[100], ssqFinal=0; @@ -204,21 +215,25 @@ cblas_dnrm21( const long int N, const double *X, const int incX) if (N <= 0 || incX <= 0) return 0; else if (N == 1) return fabs(X[0]); -#pragma omp parallel private(tid,nthreads,ix) + +////#pragma omp parallel private(tid,nthreads,ix) { + + /* #ifdef OMP - tid = omp_get_thread_num(); + tid = omp_get_thread_num(); nthreads = omp_get_num_threads(); if(nthreads>100) exit(1); #endif - + */ -#pragma omp for +////#pragma omp for for (long i = 0; i < N; i++) { ix=incX*i; ssq[tid] += X[ix]*X[ix]; } -} // pragma +} +// pragma for(int j=0;j<100;j++) ssqFinal+=ssq[j]; @@ -226,7 +241,7 @@ for(int j=0;j<100;j++) return sqrt(ssqFinal); } - +//FV_ not used ?? double cblas_dnrm22( const long int N, const double *X, const int incX) { @@ -243,14 +258,14 @@ cblas_dnrm22( const long int N, const double *X, const int incX) if (N <= 0 || incX <= 0) return 0; else if (N == 1) return fabs(X[0]); -#pragma omp parallel private(ix) -{ -#ifdef OMP - tid = omp_get_thread_num(); - nthreads = omp_get_num_threads(); - if(nthreads>100) exit(1); -#endif -#pragma omp for +///#pragma omp parallel private(ix) +////{ +////#ifdef OMP +//// tid = omp_get_thread_num(); +//// nthreads = omp_get_num_threads(); +//// if(nthreads>100) exit(1); +////#endif +////#pragma omp for for (i = 0; i < N; i++) { ix=incX*i; const double x = X[ix]; @@ -269,7 +284,7 @@ cblas_dnrm22( const long int N, const double *X, const int incX) } resultSqr[tid]=(scale[tid] * sqrt(ssq[tid]))*(scale[tid] * sqrt(ssq[tid])); -}// pragma +////}// pragma double resultFinal=0.0; for(int j=0;j<100;j++) resultFinal+=resultSqr[j]; @@ -301,6 +316,7 @@ void cblas_dscal(const long int N, const double alpha, double *X, const int incX } } +//FV_ not used ?? void cblas_dscal1(const long int N, const double alpha, double *X, const int incX) { @@ -312,14 +328,14 @@ cblas_dscal1(const long int N, const double alpha, double *X, const int incX) if (incX > 0) ix=0; else ix=((N) - 1) * (-(incX)); -#pragma omp parallel shared(ix) -{ +////#pragma omp parallel shared(ix) +/////{ long ixThread; long ixThreadOffset=ix; -#pragma omp for +/////#pragma omp for for (i = 0; i < N; i++) { ixThread=ixThreadOffset+incX*i; X[ixThread] *= alpha; } -}// end pragma +/////}// end pragma } diff --git a/memRequest.c b/memRequest.c old mode 100755 new mode 100644 diff --git a/solvergaiaSim.c b/solvergaiaSim.c index d001f9a..02dcb17 100644 --- a/solvergaiaSim.c +++ b/solvergaiaSim.c @@ -5,9 +5,9 @@ M.G. Lattanzi, A. Vecchiato, B. Bucciarelli (23 May 1996) A. Vecchiato, R. Morbidelli for the Fortran 90 version with dynamical memory allocation (21 March 2005) - + A. Vecchiato, June 16, 2008 - + Version 2.1 , Feb 8, 2012 Version history: - version 2.1, Feb 8 2012 - Added debug mode @@ -16,8 +16,6 @@ - version 5.0 - May 2013 from Ugo Becciani and Alberto Vecchiato */ - - //#include <string.h> #include <stdio.h> #include <stdlib.h> @@ -34,7 +32,6 @@ #define MAX_CONSTR 1000 - long instr_hash(int FoV, int CCD, int PixelColumn, int TimeInterval); long randlong(long max); long randlong1(long min, long max); @@ -42,505 +39,581 @@ int randint(int max); int randint1(int min, int max); int fill_extract(long *values, long *pos_min, long pos_max, long *number); - - /* Start of main program */ -int main(int argc, char **argv) { - int debugMode,wrsol; +int main(int argc, char **argv) +{ + int debugMode, wrsol; int i; - - int idtest=0, precond=1; + + int idtest = 0, precond = 1; double srIDtest, pert; - - int inputDirOpt=0, outputDirOpt=0, inputDirLen; - char inputDir[1024]="", outputDir[1024]="",wrfileDir[1024]=""; + + int inputDirOpt = 0, outputDirOpt = 0, inputDirLen; + char inputDir[1024] = "", outputDir[1024] = "", wrfileDir[1024] = ""; char wpath[1024]; - size_t sizePath=1020; - + size_t sizePath = 1020; + char filenameSolProps[150]; char filenameSolPropsFinal[150]; - char filenameAstroResults[150]; /* file storing the Astrometric Parameters */ - char filenameAttResults[150]; /* file storing the Attitude Parameters */ - char filenameInstrResults[150]; /* file storing the Instrument Parameters */ + char filenameAstroResults[150]; /* file storing the Astrometric Parameters */ + char filenameAttResults[150]; /* file storing the Attitude Parameters */ + char filenameInstrResults[150]; /* file storing the Instrument Parameters */ char filenameGlobalResults[150]; /* file storing the Global Parameters */ - + long ii, jj, kk; long sphereId; // Id of the sphere to be solved - long idum; // variable to initialize the random number generator aggiunta la variabile per inizializzare ran2() - + long idum; // variable to initialize the random number generator aggiunta la variabile per inizializzare ran2() + // LSQR input parameters - long itnlim; // maximum number of iteration allowed for the LSQR convergence + long itnlim; // maximum number of iteration allowed for the LSQR convergence double damp, atol, btol, conlim; // other LSQR input parameters - double aTol; //read by command line, overrides atol if >=0 - + double aTol; //read by command line, overrides atol if >=0 + // LSQR output parameters - int istop; // LSQR stopping condition - int itn; // LSQR iteration number + int istop; // LSQR stopping condition + int itn; // LSQR iteration number double anorm, acond, rnorm, arnorm, xnorm; // other LSQR output parameters - + // Properties of the system to be solved // Astrometric parameters: - long nStar; // number of stars - short nAstroP; // number of astrometric parameters for each observation - - short nAstroPSolved,nInstrPSolved; // number of astrometric and instrumental parameters taken as unknowns in the system of equations - int *mapAstroP; // indeces of the solved astrometric parameters - int lsInstrFlag,ssInstrFlag,nuInstrFlag,maInstrFlag; - int nElemIC=0,nOfInstrConstr=0; - int nOfInstrConstrLSAL=0, nElemICLSAL=0, nOfInstrConstrLSAC=0, nElemICLSAC=0 , nOfInstrConstrSS=0 ,nElemICSS=0; + long nStar; // number of stars + short nAstroP; // number of astrometric parameters for each observation + + short nAstroPSolved, nInstrPSolved; // number of astrometric and instrumental parameters taken as unknowns in the system of equations + int *mapAstroP; // indeces of the solved astrometric parameters + int lsInstrFlag, ssInstrFlag, nuInstrFlag, maInstrFlag; + int nElemIC = 0, nOfInstrConstr = 0; + int nOfInstrConstrLSAL = 0, nElemICLSAL = 0, nOfInstrConstrLSAC = 0, nElemICLSAC = 0, nOfInstrConstrSS = 0, nElemICSS = 0; // Attitude parameters: - - - long nDegFreedomAtt=0; // number of degrees of freedom for each attitude axis - long cCDLSAACZP=14; // CCD light sensitive area AC zero point - short nAttAxes=0, nAttParAxis; // number of attitude axes to be reconstructed, number of non-zero attitude coefficients per obs. & axis - short nAttP=0; // number of attitude parameters for each observation + + long nDegFreedomAtt = 0; // number of degrees of freedom for each attitude axis + long cCDLSAACZP = 14; // CCD light sensitive area AC zero point + short nAttAxes = 0, nAttParAxis; // number of attitude axes to be reconstructed, number of non-zero attitude coefficients per obs. & axis + short nAttP = 0; // number of attitude parameters for each observation // Instrument parameters: long instrSetUp; // number coding the set up of the instrument in terms of: # of FoVs, # of CCDs, # of pixel columns, # of time intervals short nInstrP; // number of instrument parameters for each observation // Global parameters: - short nGlobP; // number of global parameters - - long nobs; // number of observations - long nConstrLong, nConstrLat, nConstrMuLong, nConstrMuLat; // number of constraints for the astrometric parameters + short nGlobP; // number of global parameters + + long nobs; // number of observations + long nConstrLong, nConstrLat, nConstrMuLong, nConstrMuLat; // number of constraints for the astrometric parameters long *constrLongId, *constrLatId, *constrMuLongId, *constrMuLatId; // arrays with the gsrIDs of the constrained sources - double *constrLongW, *constrLatW, *constrMuLongW, *constrMuLatW; // arrays with the weights of the constraints - double extConstrW; // weight of the null space constraint equations - double barConstrW; // weight of the baricentric constraint equations - const double attExtConstrFact=-0.5; // the coefficients of the attitude part of the null space constraint equations must be multiplied by a factor -1/2 - + double *constrLongW, *constrLatW, *constrMuLongW, *constrMuLatW; // arrays with the weights of the constraints + double extConstrW; // weight of the null space constraint equations + double barConstrW; // weight of the baricentric constraint equations + const double attExtConstrFact = -0.5; // the coefficients of the attitude part of the null space constraint equations must be multiplied by a factor -1/2 + // Variables to be read from the GsrSystemRows - + // Internal variables long nAstroParam; - int nAttParam, nInstrParam, nGlobalParam,nInstrParamTot; // total number of unknowns for the Astrometric, Attitude, Instrument, and Global parameters respectively - int nparam; // total number of unknowns + int nAttParam, nInstrParam, nGlobalParam, nInstrParamTot; // total number of unknowns for the Astrometric, Attitude, Instrument, and Global parameters respectively + int nparam; // total number of unknowns long nunk, nunkSplit, nConstr; - long ncoeff, ielem, global_ielem, precnofrows,global_precnofrows, ncolumn, nrowsToRead; + long ncoeff, ielem, global_ielem, precnofrows, global_precnofrows, ncolumn, nrowsToRead; long offsetAttParam, offsetInstrParam, offsetGlobParam, VroffsetAttParam; // offests for the Attitude, Instrument, and Global columns of the coefficient matrix - unsigned long int totmem, nElements; // total required memory and temporary variable to store the memory being allocated - long VrIdAstroPDimMax=0; // - long VrIdAstroPDim=0; // + unsigned long int totmem, nElements; // total required memory and temporary variable to store the memory being allocated + long VrIdAstroPDimMax = 0; // + long VrIdAstroPDim = 0; // long VrIdAstroPDimRecv; int offset; long nObsxStar, nobsOri; - int nfileProc=3; - int addElementAtt=0; - int addElementextStar=0; - int addElementbarStar=0; - int nOfElextObs=0; - int nOfElBarObs=0; + int nfileProc = 3; + int addElementAtt = 0; + int addElementextStar = 0; + int addElementbarStar = 0; + int nOfElextObs = 0; + int nOfElBarObs = 0; double *attNS; - // Array arguments of the LSQR function - double *knownTerms, *vVect, *wVect, *xSolution, *standardError; // arrays containing the known terms (knownterms), the bidiagonalization (wVect, wVect), the unknowns (xSolution), and the estimated variances (standardError) - long int *matrixIndex; // ia[i] contains the column number of the coefficient systemMatrix[i] + double *knownTerms, *vVect, *wVect, *xSolution, *standardError; + + double **vVect_aux_AttP; + double **vVect_aux_InstP; + + // arrays containing the known terms (knownterms), the bidiagonalization (wVect, wVect), the unknowns (xSolution), and the estimated variances (standardError) + long int *matrixIndex; // ia[i] contains the column number of the coefficient systemMatrix[i] int *instrConst; - int *instrCol; // columns on each observation for instumental Parameters - int * instrConstrIlung; // vector containing the length of each instrConstr eq. + int *instrCol; // columns on each observation for instumental Parameters + int *instrConstrIlung; // vector containing the length of each instrConstr eq. double *systemMatrix, *preCondVect; // array of the non-zero coefficients of the system and of the column normalization respectively - int wgInstrCoeff=1; - + int wgInstrCoeff = 1; + ///////////////////// // Arrays containing the solution coming from the LSQR - double *xAstro, *standardErrorAstro; // solution and standard errors for the Astrometric parameters - double *xAtt, *standardErrorAtt; // solution and standard errors for the Attitude parameters - double *xInstr, *standardErrorInstr; // solution and standard errors for the Instrument parameters + double *xAstro, *standardErrorAstro; // solution and standard errors for the Astrometric parameters + double *xAtt, *standardErrorAtt; // solution and standard errors for the Attitude parameters + double *xInstr, *standardErrorInstr; // solution and standard errors for the Instrument parameters double *xGlobal, *standardErrorGlobal; // solution and standard errors for the Global parameters - - + // file pointers - FILE *fpSolProps,*fpSolPropsFinal,*fpSolPropsFileBin; + FILE *fpSolProps, *fpSolPropsFinal, *fpSolPropsFileBin; FILE *fpMI, *fpSM, *fpII, *fpKT, *fpCPR; FILE *fpAstroR, *fpAttR, *fpInstrR, *fpGlobR, *ffcont; - + time_t seconds[10], tot_sec[10]; seconds[0] = time(NULL); double timeToReadFiles; - + //MPI definitions - int nproc, myid, namelen; + int nproc, myid, namelen; char processor_name[MPI_MAX_PROCESSOR_NAME]; - double startTime,endTime; - + double startTime, endTime; + // Distributed array maps - long int * mapNcoeff, * mapNoss; - long int mapNcoeffBefore, mapNossBefore; - long int mapNcoeffAfter, mapNossAfter; + long int *mapNcoeff, *mapNoss; + long int mapNcoeffBefore, mapNossBefore; + long int mapNcoeffAfter, mapNossAfter; // struct to communicate with lsqr - int timeCPR, timeLimit,itnCPR,itnCPRstop=1000000; + int timeCPR, timeLimit, itnCPR, itnCPRstop = 1000000; int itnLimit; //read by command line, overrides itnlim if >0 struct comData comlsqr; // serach for map - long lastStar=-1; - long firstStar=-1; - long lastStarConstr=-1; - long firstStarConstr=-1; - int seqStar=1; - int withFile=1; - int noConstr=0; - int zeroAtt=0, zeroInstr=0, zeroGlob=0, wrFilebin=0; + long lastStar = -1; + long firstStar = -1; + long lastStarConstr = -1; + long firstStarConstr = -1; + int seqStar = 1; + int withFile = 1; + int noConstr = 0; + int zeroAtt = 0, zeroInstr = 0, zeroGlob = 0, wrFilebin = 0; int constraintFound[MAX_CONSTR][2]; // first: number of file of the constraint; second: row in file - int rowInFile=0; - int noIter=0; - int noCPR=0; - int extConstraint=0, nEqExtConstr=0; - int barConstraint=0, nEqBarConstr=0; - int startingAttColExtConstr,endingAttColExtConstr,numOfExtAttCol,starOverlap=0,numOfExtStar,numOfBarStar; + int rowInFile = 0; + int noIter = 0; + int noCPR = 0; + int extConstraint = 0, nEqExtConstr = 0; + int barConstraint = 0, nEqBarConstr = 0; + int startingAttColExtConstr, endingAttColExtConstr, numOfExtAttCol, starOverlap = 0, numOfExtStar, numOfBarStar; char constranitFoundFileName[MAX_CONSTR][256]; - struct dirent **namelistMI; + struct dirent **namelistMI; struct nullSpace nullSpaceCk; double nullSpaceAttfact; - int autoRun=0; - float memGlobal=0; + int autoRun = 0; + float memGlobal = 0; float memGB; + int nthreads=1; //**QUI modificato a 1 da 0 + int ntasks=0; + /////////////// - for (int i=1;i<argc-1;i++) + for (int i = 1; i < argc - 1; i++) { - if(strcmp (argv[i],"-testXCode") == 0) - sleep(600); + if (strcmp(argv[i], "-testXCode") == 0) + sleep(600); } MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nproc); MPI_Comm_rank(MPI_COMM_WORLD, &myid); - MPI_Get_processor_name(processor_name,&namelen); - startTime= MPI_Wtime(); + MPI_Get_processor_name(processor_name, &namelen); + startTime =0;// MPI_Wtime(); // Initialize the random number generator for each PE - idum=-((long)startTime+myid); - - - if (argc == 1) { - if(myid==0){ + idum = -((long)startTime + myid); + + if (argc == 1) + { + if (myid == 0) + { printf("Usage: solvergaiaSim [-auto] [-memGlobal value] [-IDtest [value] -noFile -noConstr -numFilexproc nfileProc -Precond [on|off] -timeCPR hours -timelimit hours -itnCPR numberOfIterations -noCPR -itnlimit numberOfIterations -atol value -inputDir inputdir -outputDir outputdir -zeroAtt -zeroInstr -zeroGlob -wgic value]] -wrfilebin writedir -wrsol -noiter -extConstr weight -barConstr weight filename\n\n"); } MPI_Finalize(); exit(EXIT_FAILURE); } - debugMode=0; - wrsol=0; - int testTime=0; - short testSolved=-1; - nAstroPSolved=-1; - idtest=0; - + debugMode = 0; + wrsol = 0; + int testTime = 0; + short testSolved = -1; + nAstroPSolved = -1; + idtest = 0; + //idtest=1; // IDTest forced for the simulator - - timeCPR=DEFAULT_TIMECPR; - timeLimit=DEFAULT_TIMELIMIT; - itnCPR=DEFAULT_ITNCPR; - itnLimit=0; - aTol=-1.0; - if(strcmp (argv[1],"-auto") == 0){ + + timeCPR = DEFAULT_TIMECPR; + timeLimit = DEFAULT_TIMELIMIT; + itnCPR = DEFAULT_ITNCPR; + itnLimit = 0; + aTol = -1.0; + if (strcmp(argv[1], "-auto") == 0) + { printf(" solvergaiaSim -auto "); - idtest=1; - srIDtest=1; - withFile=0; - noConstr=1; - noCPR=1; - itnLimit=20000; - wgInstrCoeff=100; - barConstraint=1; - nEqBarConstr=DEFAULT_BARCONSTROWS; - barConstrW=10.0; - autoRun=1; - for (int i=2;i<argc-1;i++){ - if(strcmp (argv[i],"-memGlobal") == 0) - { - memGlobal=atof(argv[i+1]); - printf("-memGlobal %f",memGlobal); - } - + idtest = 1; + srIDtest = 1; + withFile = 0; + noConstr = 1; + noCPR = 1; + itnLimit = 5; + wgInstrCoeff = 100; + //edited FV + barConstraint = 1; + //barConstraint = 0; + nEqBarConstr = DEFAULT_BARCONSTROWS; + barConstrW = 10.0; + autoRun = 1; + for (int i = 2; i < argc - 1; i++) + { + if (strcmp(argv[i], "-memGlobal") == 0) + { + memGlobal = atof(argv[i + 1]); + printf("-memGlobal %f", memGlobal); + } } printf("\n\n"); } - - for (int i=1;i<argc-1;i++) - { - if(strcmp (argv[i],"-IDtest") == 0) + + for (int i = 1; i < argc - 1; i++) + { + if (strcmp(argv[i], "-IDtest") == 0) + { + idtest = 1; + srIDtest = atof(argv[i + 1]); + } + if (strcmp(argv[i], "-Precond") == 0) // aggiunto precond on/off + if (strcmp(argv[i + 1], "off") == 0) // aggiunto precond on/off + precond = 0; + + if (strcmp(argv[i], "-noFile") == 0) + withFile = 0; + if (strcmp(argv[i], "-noConstr") == 0) + noConstr = 1; + + if (strcmp(argv[i], "-numFilexproc") == 0) { - idtest=1; - srIDtest=atof(argv[i+1]); + nfileProc = atoi(argv[i + 1]); + if (nfileProc <= 0) + nfileProc = 3; } - if(strcmp (argv[i],"-Precond") == 0) // aggiunto precond on/off - if(strcmp (argv[i+1],"off") == 0) // aggiunto precond on/off - precond=0; - - if(strcmp (argv[i],"-noFile") == 0) withFile=0; - if(strcmp (argv[i],"-noConstr") == 0) noConstr=1; - - - if(strcmp (argv[i],"-numFilexproc") == 0) + if (strcmp(argv[i], "-timeCPR") == 0) { - nfileProc=atoi(argv[i+1]); - if(nfileProc <=0) nfileProc=3; + testTime = atoi(argv[i + 1]); + if (testTime > 0) + timeCPR = testTime; } - if(strcmp (argv[i],"-timeCPR") == 0) + if (strcmp(argv[i], "-timelimit") == 0) { - testTime=atoi(argv[i+1]); - if(testTime >0) timeCPR=testTime; + testTime = atoi(argv[i + 1]); + if (testTime > 0) + timeLimit = testTime; } - if(strcmp (argv[i],"-timelimit") == 0) + + if (strcmp(argv[i], "-itnCPR") == 0) { - testTime=atoi(argv[i+1]); - if(testTime >0) timeLimit=testTime; + testTime = atoi(argv[i + 1]); + if (testTime > 0) + itnCPR = testTime; } - - if(strcmp (argv[i],"-itnCPR") == 0) + if (strcmp(argv[i], "-noCPR") == 0) { - testTime=atoi(argv[i+1]); - if(testTime >0) itnCPR=testTime; + noCPR = 1; } - if(strcmp (argv[i],"-noCPR") == 0) + if (strcmp(argv[i], "-itnlimit") == 0) { - noCPR=1; + testTime = atoi(argv[i + 1]); + if (testTime > 0) + itnLimit = testTime; } - if(strcmp (argv[i],"-itnlimit") == 0) + if(strcmp (argv[i],"-tasks") == 0) { - testTime=atoi(argv[i+1]); - if(testTime >0) itnLimit=testTime; + ntasks=atoi(argv[i+1]); + if(ntasks <=0) ntasks=0; } - if(strcmp (argv[i],"-atol") == 0) + if (strcmp(argv[i], "-atol") == 0) { - double dummy=atof(argv[i+1]); - if(dummy >=0) aTol=dummy; + double dummy = atof(argv[i + 1]); + if (dummy >= 0) + aTol = dummy; } - if(strcmp (argv[i],"-zeroAtt") == 0) + if (strcmp(argv[i], "-zeroAtt") == 0) { - zeroAtt=1; + zeroAtt = 1; } - if(strcmp (argv[i],"-zeroInstr") == 0) + if (strcmp(argv[i], "-zeroInstr") == 0) { - zeroInstr=1; + zeroInstr = 1; } - if(strcmp (argv[i],"-zeroGlob") == 0) + if (strcmp(argv[i], "-zeroGlob") == 0) { - zeroGlob=1; + zeroGlob = 1; } - if(strcmp (argv[i],"-wgic") == 0) + if (strcmp(argv[i], "-wgic") == 0) { - wgInstrCoeff=atoi(argv[i+1]); - if(wgInstrCoeff<=0) wgInstrCoeff=1; + wgInstrCoeff = atoi(argv[i + 1]); + if (wgInstrCoeff <= 0) + wgInstrCoeff = 1; } // inputDir e outputDir - - if(strcmp (argv[i],"-inputDir") == 0) + + if (strcmp(argv[i], "-inputDir") == 0) { - sprintf(inputDir, "%s", argv[i+1]); - inputDirOpt=1; + sprintf(inputDir, "%s", argv[i + 1]); + inputDirOpt = 1; } - - if(strcmp (argv[i],"-outputDir") == 0) + + if (strcmp(argv[i], "-outputDir") == 0) { - sprintf(outputDir, "%s", argv[i+1]); - outputDirOpt=1; + sprintf(outputDir, "%s", argv[i + 1]); + outputDirOpt = 1; } - + // Fine input e output Dir - - if(strcmp (argv[i],"-debug") == 0) - debugMode=1; - - if(strcmp (argv[i],"-wrsol") == 0){ - wrsol=1; - } - - if(strcmp (argv[i],"-noiter") == 0){ - noIter=1; - } - - if(strcmp (argv[i],"-wrfilebin") == 0) - { - sprintf(wrfileDir, "%s", argv[i+1]); - wrFilebin=1; - } - if(strcmp (argv[i],"-extConstr") == 0) - { - extConstraint=1; //extendet external constraint - nEqExtConstr=DEFAULT_EXTCONSTROWS; - extConstrW=atof(argv[i+1]); - if(extConstrW==0.0){ - printf("ERROR: PE=%d -extConstr option given with no value or zero value ==> %le. Aborting\n",myid,extConstrW); - MPI_Abort(MPI_COMM_WORLD,1); + + if (strcmp(argv[i], "-debug") == 0) + debugMode = 1; + + if (strcmp(argv[i], "-wrsol") == 0) + { + wrsol = 1; + } + + if (strcmp(argv[i], "-noiter") == 0) + { + noIter = 1; + } + + if (strcmp(argv[i], "-wrfilebin") == 0) + { + sprintf(wrfileDir, "%s", argv[i + 1]); + wrFilebin = 1; + } + if (strcmp(argv[i], "-extConstr") == 0) + { + extConstraint = 1; //extendet external constraint + nEqExtConstr = DEFAULT_EXTCONSTROWS; + extConstrW = atof(argv[i + 1]); + if (extConstrW == 0.0) + { + printf("ERROR: PE=%d -extConstr option given with no value or zero value ==> %le. Aborting\n", myid, extConstrW); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } } - if(strcmp (argv[i],"-barConstr") == 0) + if (strcmp(argv[i], "-barConstr") == 0) { - barConstraint=1; //extendet external constraint - nEqBarConstr=DEFAULT_BARCONSTROWS; - barConstrW=atof(argv[i+1]); - if(barConstrW==0.0){ - printf("ERROR: PE=%d -barConstr option given with no value or zero value ==> %le. Aborting\n",myid,barConstrW); - MPI_Abort(MPI_COMM_WORLD,1); + barConstraint = 1; //extendet external constraint + nEqBarConstr = DEFAULT_BARCONSTROWS; + barConstrW = atof(argv[i + 1]); + if (barConstrW == 0.0) + { + printf("ERROR: PE=%d -barConstr option given with no value or zero value ==> %le. Aborting\n", myid, barConstrW); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } } - - } - if (extConstraint) noConstr=2; - if (barConstraint) noConstr=2; - - - if(myid==0) - { - printf("Execution of solvergaia Simulator version %s on %d mpi-tasks\n solvergaiaSim ",VER,nproc); - if(idtest)printf ("-IDtest %le ", srIDtest); - if(precond)printf ("-Precond on"); - else printf ("-Precond off"); - if(nfileProc!=3) printf ("-numFilexproc %d ",nfileProc); - if(wrFilebin) printf(" -wrfilebin %s ",wrfileDir); - if(!withFile) printf(" -noFile "); - if(itnLimit>0) printf(" -itnlimit %d ",itnLimit); - if(noCPR>0) printf(" -noCPR "); - if(itnCPR!= DEFAULT_ITNCPR) printf(" -itnCPR %d ", itnCPR); - if(zeroAtt) printf(" -zeroAtt "); - if(noConstr==1) printf(" -noConstr "); - if(zeroInstr) printf(" -zeroInstr "); - if(zeroGlob) printf(" -zeroGlob "); - if(inputDirOpt) printf(" -inputDir %s ", inputDir); - if(outputDirOpt) printf(" -outputDir %s ", outputDir); - if(wrsol) printf(" -wrsol "); - if(noIter) printf(" -noiter "); - if(debugMode) printf(" -debug "); - if(extConstraint)printf("-extConstr %le ",extConstrW); - if(barConstraint)printf("-barConstr %le ",barConstrW); - printf("-wgic %d", wgInstrCoeff); - if(!autoRun) printf(" %s\n",argv[argc-1]); - if(extConstraint && barConstraint) { + } + if (extConstraint) + noConstr = 2; + if (barConstraint) + noConstr = 2; + + if (myid == 0) + { + printf("Execution of solvergaia Simulator version %s on %d mpi-tasks\n solvergaiaSim ", VER, nproc); + if (idtest) + printf("-IDtest %le ", srIDtest); + if (precond) + printf("-Precond on"); + else + printf("-Precond off"); + if (nfileProc != 3) + printf("-numFilexproc %d ", nfileProc); + if (wrFilebin) + printf(" -wrfilebin %s ", wrfileDir); + if (!withFile) + printf(" -noFile "); + if (itnLimit > 0) + printf(" -itnlimit %d ", itnLimit); + if (noCPR > 0) + printf(" -noCPR "); + if (itnCPR != DEFAULT_ITNCPR) + printf(" -itnCPR %d ", itnCPR); + if (zeroAtt) + printf(" -zeroAtt "); + if (noConstr == 1) + printf(" -noConstr "); + if (zeroInstr) + printf(" -zeroInstr "); + if (zeroGlob) + printf(" -zeroGlob "); + if (inputDirOpt) + printf(" -inputDir %s ", inputDir); + if (outputDirOpt) + printf(" -outputDir %s ", outputDir); + if (wrsol) + printf(" -wrsol "); + if (noIter) + printf(" -noiter "); + if (debugMode) + printf(" -debug "); + if(ntasks>0) + printf(" -tasks %d ",ntasks); + if (extConstraint) + printf("-extConstr %le ", extConstrW); + if (barConstraint) + printf("-barConstr %le ", barConstrW); + printf("-wgic %d", wgInstrCoeff); + if (!autoRun) + printf(" %s\n", argv[argc - 1]); + if (extConstraint && barConstraint) + { printf("Error: baricentric anld null space constraints are mutually exclusive. Aborting\n"); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(wrFilebin && strcmp(inputDir, wrfileDir)==0){ + if (wrFilebin && strcmp(inputDir, wrfileDir) == 0) + { printf("inputDir and wrfilebinDir are the same. Execution Aborted.\n"); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); - } + printf ("\n"); } ///////////////// - getcwd(wpath,sizePath); - if(!inputDirOpt) + getcwd(wpath, sizePath); + if (!inputDirOpt) strcpy(inputDir, wpath); - printf("Process %d running on %s\n",myid,processor_name); -#ifdef OMP -#pragma omp parallel + printf("Process %d running on %s\n", myid, processor_name); + ////#ifdef OMP + ///#pragma omp task { - int tid = omp_get_thread_num(); - int nthreads = omp_get_num_threads(); - printf("PE=%d on processor %s total num of threads =%d ID thread =%d \n",myid, processor_name,nthreads,tid); - - } + // int tid = omp_get_thread_num(); + /* + const char* s = getenv("NX_SMP_WORKERS");//? "":"1"; + if(s ==NULL) + s="1"; + nthreads = atoi(s); //QUI** verifica che la chiamata ritorni il numero di tasks allocati!! + */ + + //nthreads sono attuatori + // ntasks sono la mia suddivisione +#ifdef OMP + nthreads=omp_get_num_threads(); //**QUI immagino che nthreads>=1 (se 0 non fiunziona!) #endif - nullSpaceAttfact=1.0*attExtConstrFact*extConstrW; - comlsqr.extConstrW=extConstrW; - comlsqr.nullSpaceAttfact=nullSpaceAttfact; - comlsqr.barConstrW=barConstrW; - - - if(inputDirOpt) - { - if(myid==0) printf("Checking input directory %s ... ", inputDir); - if(!(chdir(inputDir)==0)) { + if(ntasks==0) + ntasks=nthreads; + printf("PE=%d on processor %s total num of threads =%d, ntasks=%d\n",myid, processor_name,nthreads,ntasks); + } + ////#pragma omp taskwait + ////#endif + nullSpaceAttfact = 1.0 * attExtConstrFact * extConstrW; + comlsqr.extConstrW = extConstrW; + comlsqr.nullSpaceAttfact = nullSpaceAttfact; + comlsqr.barConstrW = barConstrW; + + if (inputDirOpt) + { + if (myid == 0) + printf("Checking input directory %s ... ", inputDir); + if (!(chdir(inputDir) == 0)) + { printf("Input directory does not exist. Aborting\n"); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } chdir(wpath); - if(myid==0) printf("success.\n"); + if (myid == 0) + printf("success.\n"); } - inputDirLen=strlen(inputDir); - sprintf(filenameSolProps, "%s", argv[argc-1]); - sprintf(filenameSolPropsFinal,"GsrFinal_%s", argv[argc-1]); - - if(outputDirOpt) + inputDirLen = strlen(inputDir); + sprintf(filenameSolProps, "%s", argv[argc - 1]); + sprintf(filenameSolPropsFinal, "GsrFinal_%s", argv[argc - 1]); + + if (outputDirOpt) { - if(myid==0) printf("Checking output directory %s ...", outputDir); - if(!(chdir(outputDir)==0)) { + if (myid == 0) + printf("Checking output directory %s ...", outputDir); + if (!(chdir(outputDir) == 0)) + { printf("Output directory does not exist on PE %d. Aborting\n", myid); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(myid==0) printf("success.\n"); + if (myid == 0) + printf("success.\n"); } - + ///////////// Initialize the output filename - sprintf(filenameAstroResults, "%s", "GsrAstroParamSolution.bin"); // file storing the Astrometric Parameters - sprintf(filenameAttResults, "%s","GsrAttitudeParamSolution.bin"); // file storing the Attitude Parameters - sprintf(filenameInstrResults, "%s","GsrInstrParamSolution.bin"); // file storing the Instrument Parameters - sprintf(filenameGlobalResults, "%s","GsrGlobalParamSolution.bin"); // file storing the Global Parameters - - -// instrConst=(int *) calloc(DEFAULT_NINSTRINDEXES+1 , sizeof(int)); - instrConst=(int *) calloc(DEFAULT_NINSTRINDEXES , sizeof(int)); - nAttParAxis=4; + sprintf(filenameAstroResults, "%s", "GsrAstroParamSolution.bin"); // file storing the Astrometric Parameters + sprintf(filenameAttResults, "%s", "GsrAttitudeParamSolution.bin"); // file storing the Attitude Parameters + sprintf(filenameInstrResults, "%s", "GsrInstrParamSolution.bin"); // file storing the Instrument Parameters + sprintf(filenameGlobalResults, "%s", "GsrGlobalParamSolution.bin"); // file storing the Global Parameters + + // instrConst=(int *) calloc(DEFAULT_NINSTRINDEXES+1 , sizeof(int)); + instrConst = (int *)calloc(DEFAULT_NINSTRINDEXES, sizeof(int)); + nAttParAxis = 4; //START READING filenameSolProps //START READING filenameSolProps GsrSolProps.dat - if(myid==0 && wrFilebin){ + if (myid == 0 && wrFilebin) + { chdir(wpath); chdir(wrfileDir); - fpSolPropsFileBin=fopen(filenameSolProps,"w"); + fpSolPropsFileBin = fopen(filenameSolProps, "w"); } chdir(wpath); - if(inputDirOpt) chdir(inputDir); - if(myid==0) - { - if (autoRun){ - sphereId=0; - atol= 0.000000; - btol= 0.000000; - conlim= 10000000000000.000000; - itnlim= 2000; - if(itnLimit>0) - itnlim=itnLimit; - damp= 0.000000; - nStar= 10000; - nAstroP= 5; - nAstroPSolved= 5; - nConstrLat= 0; - nConstrLong= 0; - nConstrMuLat= 0; - nConstrMuLong= 0; - nDegFreedomAtt= 230489; - nAttAxes= 3; - instrConst[0]= 1; - instrConst[1]= 62; - instrConst[2]= 1966; - instrConst[3]= 22; - nInstrP= 6; - nInstrPSolved= 6; - lsInstrFlag= 1; - ssInstrFlag= 1; - nuInstrFlag= 1; - maInstrFlag= 1; - nOfInstrConstr= -1; - nElemIC= -1; - nGlobP= 0; - nobs= 2400000; + if (inputDirOpt) + chdir(inputDir); + if (myid == 0) + { + if (autoRun) + { + sphereId = 0; + atol = 0.000000; + btol = 0.000000; + conlim = 10000000000000.000000; + itnlim = 2000; + if (itnLimit > 0) + itnlim = itnLimit; + damp = 0.000000; + nStar = 10000; + nAstroP = 5; + nAstroPSolved = 5; + nConstrLat = 0; + nConstrLong = 0; + nConstrMuLat = 0; + nConstrMuLong = 0; + nDegFreedomAtt = 230489; + nAttAxes = 3; + instrConst[0] = 1; + instrConst[1] = 62; + instrConst[2] = 1966; + instrConst[3] = 22; + nInstrP = 6; + nInstrPSolved = 6; + lsInstrFlag = 1; + ssInstrFlag = 1; + nuInstrFlag = 1; + maInstrFlag = 1; + nOfInstrConstr = -1; + //edited FV + nElemIC = -1; + //nElemIC = 0; + nGlobP = 0; + nobs = 2400000; nAstroParam = nStar * nAstroPSolved; nAttParam = nDegFreedomAtt * nAttAxes; - if(nDegFreedomAtt<4) nAttParAxis=nDegFreedomAtt; - if(nDegFreedomAtt) nAttP = nAttAxes * nAttParAxis; - long nFoVs=1+instrConst[0]; - long nCCDs=instrConst[1]; - long nPixelColumns=instrConst[2]; - long nTimeIntervals=instrConst[3]; + if (nDegFreedomAtt < 4) + nAttParAxis = nDegFreedomAtt; + if (nDegFreedomAtt) + nAttP = nAttAxes * nAttParAxis; + long nFoVs = 1 + instrConst[0]; + long nCCDs = instrConst[1]; + long nPixelColumns = instrConst[2]; + long nTimeIntervals = instrConst[3]; // tot. instr. param. = nCCDs (Cmag) + nFoVs*nCCDs (Cnu) + nCCDs*nPixelColumns (delta_eta) + 3*nFoVs*nCCDs*nTimeIntervals (Delta_eta) + nCCDs*nPixelColumns (delta_zeta) + 3*nFoVs*nCCDs*nTimeIntervals (Delta_zeta) // added flags switch on and off the appropriate kind of parameters - nInstrParam = maInstrFlag*nCCDs+nuInstrFlag*nFoVs*nCCDs+ssInstrFlag*2*nCCDs*nPixelColumns+lsInstrFlag*2*3*nFoVs*nCCDs*nTimeIntervals; - nInstrParamTot = nCCDs+ nFoVs*nCCDs+ 2*nCCDs*nPixelColumns+2*3*nFoVs*nCCDs*nTimeIntervals; - if(nInstrP==0) nInstrParamTot=0; + nInstrParam = maInstrFlag * nCCDs + nuInstrFlag * nFoVs * nCCDs + ssInstrFlag * 2 * nCCDs * nPixelColumns + lsInstrFlag * 2 * 3 * nFoVs * nCCDs * nTimeIntervals; + nInstrParamTot = nCCDs + nFoVs * nCCDs + 2 * nCCDs * nPixelColumns + 2 * 3 * nFoVs * nCCDs * nTimeIntervals; + if (nInstrP == 0) + nInstrParamTot = 0; nGlobalParam = nGlobP; - + nparam = nAstroPSolved + nAttP + nInstrPSolved + nGlobP; - if(memGlobal!=0){ - memGB=simfullram(nStar,nobs,memGlobal,nparam,nAttParam,nInstrParam); - printf("Running with memory %f GB, nStar=%d nobs=%ld\n",memGB, nStar,nobs); + if (memGlobal != 0) + { + memGB = simfullram(nStar, nobs, memGlobal, nparam, nAttParam, nInstrParam); + printf("Running with memory %f GB, nStar=%d nobs=%ld\n", memGB, nStar, nobs); } printf("sphereId= %7ld\n", sphereId); printf("atol= %18.15lf\n", atol); @@ -557,7 +630,7 @@ int main(int argc, char **argv) { printf("nConstrMuLong= %5ld\n", nConstrMuLong); printf("nDegFreedomAtt= %7ld\n", nDegFreedomAtt); printf("nAttAxes= %7hd\n", nAttAxes); - printf("nFovs= %7d ", instrConst[0]+1); + printf("nFovs= %7d ", instrConst[0] + 1); printf("(instrConst[0])= %7d\n", instrConst[0]); printf("nCCDs= %7d\n", instrConst[1]); printf("nPixelColumns= %7d\n", instrConst[2]); @@ -572,616 +645,751 @@ int main(int argc, char **argv) { printf("nElemIC= %7d\n", nElemIC); printf("nGlobP= %7hd\n", nGlobP); printf("nObs= %10ld\n", nobs); - if(wrFilebin){ - fprintf(fpSolPropsFileBin,"sphereId= %ld\n", sphereId); - fprintf(fpSolPropsFileBin,"atol= %lf\n", atol); - fprintf(fpSolPropsFileBin,"btol= %lf\n", btol); - fprintf(fpSolPropsFileBin,"conlim= %lf\n", conlim); - fprintf(fpSolPropsFileBin,"itnlim= %ld\n", itnlim); - fprintf(fpSolPropsFileBin,"damp= %lf\n", damp); - fprintf(fpSolPropsFileBin,"nStar= %ld\n", nStar); - fprintf(fpSolPropsFileBin,"nAstroP= %hd\n", nAstroP); - fprintf(fpSolPropsFileBin,"nAstroPSolved= %hd\n", nAstroPSolved); - fprintf(fpSolPropsFileBin,"nConstrLat= 0\n"); - fprintf(fpSolPropsFileBin,"nConstrLong= 0\n"); - fprintf(fpSolPropsFileBin,"nConstrMuLat= 0\n"); - fprintf(fpSolPropsFileBin,"nConstrMuLong= 0\n"); - fprintf(fpSolPropsFileBin,"nDegFreedomAtt= %ld\n", nDegFreedomAtt); - fprintf(fpSolPropsFileBin,"nAttAxes= %hd\n", nAttAxes); - fprintf(fpSolPropsFileBin,"nFoVs= %d\n", instrConst[0]); - fprintf(fpSolPropsFileBin,"nCCDs= %d\n", instrConst[1]); - fprintf(fpSolPropsFileBin,"nPixelColumns= %d\n", instrConst[2]); - fprintf(fpSolPropsFileBin,"nTimeIntervals= %d\n", instrConst[3]); - fprintf(fpSolPropsFileBin,"nInstrP= %hd\n", nInstrP); - fprintf(fpSolPropsFileBin,"nInstrPSolved= %hd\n", nInstrPSolved); - fprintf(fpSolPropsFileBin,"lsInstrFlag= %hd\n", lsInstrFlag); - fprintf(fpSolPropsFileBin,"ssInstrFlag= %hd\n", ssInstrFlag); - fprintf(fpSolPropsFileBin,"nuInstrFlag= %hd\n", nuInstrFlag); - fprintf(fpSolPropsFileBin,"maInstrFlag= %hd\n", maInstrFlag); - fprintf(fpSolPropsFileBin,"nOfInstrConstr= %d\n", nOfInstrConstr); - fprintf(fpSolPropsFileBin,"nElemIC= %d\n", nElemIC); - fprintf(fpSolPropsFileBin,"nGlobP= %hd\n", nGlobP); - fprintf(fpSolPropsFileBin,"nObs= %ld\n", nobs); + if (wrFilebin) + { + fprintf(fpSolPropsFileBin, "sphereId= %ld\n", sphereId); + fprintf(fpSolPropsFileBin, "atol= %lf\n", atol); + fprintf(fpSolPropsFileBin, "btol= %lf\n", btol); + fprintf(fpSolPropsFileBin, "conlim= %lf\n", conlim); + fprintf(fpSolPropsFileBin, "itnlim= %ld\n", itnlim); + fprintf(fpSolPropsFileBin, "damp= %lf\n", damp); + fprintf(fpSolPropsFileBin, "nStar= %ld\n", nStar); + fprintf(fpSolPropsFileBin, "nAstroP= %hd\n", nAstroP); + fprintf(fpSolPropsFileBin, "nAstroPSolved= %hd\n", nAstroPSolved); + fprintf(fpSolPropsFileBin, "nConstrLat= 0\n"); + fprintf(fpSolPropsFileBin, "nConstrLong= 0\n"); + fprintf(fpSolPropsFileBin, "nConstrMuLat= 0\n"); + fprintf(fpSolPropsFileBin, "nConstrMuLong= 0\n"); + fprintf(fpSolPropsFileBin, "nDegFreedomAtt= %ld\n", nDegFreedomAtt); + fprintf(fpSolPropsFileBin, "nAttAxes= %hd\n", nAttAxes); + fprintf(fpSolPropsFileBin, "nFoVs= %d\n", instrConst[0]); + fprintf(fpSolPropsFileBin, "nCCDs= %d\n", instrConst[1]); + fprintf(fpSolPropsFileBin, "nPixelColumns= %d\n", instrConst[2]); + fprintf(fpSolPropsFileBin, "nTimeIntervals= %d\n", instrConst[3]); + fprintf(fpSolPropsFileBin, "nInstrP= %hd\n", nInstrP); + fprintf(fpSolPropsFileBin, "nInstrPSolved= %hd\n", nInstrPSolved); + fprintf(fpSolPropsFileBin, "lsInstrFlag= %hd\n", lsInstrFlag); + fprintf(fpSolPropsFileBin, "ssInstrFlag= %hd\n", ssInstrFlag); + fprintf(fpSolPropsFileBin, "nuInstrFlag= %hd\n", nuInstrFlag); + fprintf(fpSolPropsFileBin, "maInstrFlag= %hd\n", maInstrFlag); + fprintf(fpSolPropsFileBin, "nOfInstrConstr= %d\n", nOfInstrConstr); + fprintf(fpSolPropsFileBin, "nElemIC= %d\n", nElemIC); + fprintf(fpSolPropsFileBin, "nGlobP= %hd\n", nGlobP); + fprintf(fpSolPropsFileBin, "nObs= %ld\n", nobs); fclose(fpSolPropsFileBin); } - }else{ - fpSolProps=fopen(filenameSolProps,"r"); - if (!fpSolProps) - { - printf("Error while open %s\n",filenameSolProps); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - - if(fscanf(fpSolProps, "sphereId= %ld\n",&sphereId) != 1) { - printf("Error reading sphereId %ld \n",sphereId); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("sphereId= %7ld\n", sphereId); - if(wrFilebin) fprintf(fpSolPropsFileBin,"sphereId= %ld\n", sphereId); - - if(fscanf(fpSolProps, "atol= %lf\n",&atol) != 1) { - printf("Error reading atol %lf \n",atol); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(aTol >=0) - atol=aTol; - printf("atol= %18.15lf\n", atol); - if(wrFilebin) fprintf(fpSolPropsFileBin,"atol= %lf\n", atol); - - if(fscanf(fpSolProps, "btol= %lf\n",&btol) != 1) { - printf("Error reading btol %lf \n",btol); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("btol= %18.15lf\n", btol); - if(wrFilebin) fprintf(fpSolPropsFileBin,"btol= %lf\n", btol); - - if(fscanf(fpSolProps, "conlim= %lf\n",&conlim) != 1) { - printf("Error reading conlim %lf \n",conlim); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("conlim= %18.15le\n", conlim); - if(wrFilebin) fprintf(fpSolPropsFileBin,"conlim= %lf\n", conlim); - - if(fscanf(fpSolProps, "itnlim= %ld\n",&itnlim) != 1) { - printf("Error reading itnlim %ld \n",itnlim); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(itnLimit>0) - itnlim=itnLimit; - printf("itnlim= %7ld\n", itnlim); - if(wrFilebin) fprintf(fpSolPropsFileBin,"itnlim= %ld\n", itnlim); - - if(fscanf(fpSolProps, "damp= %lf\n",&damp) != 1) { - printf("Error reading damp %lf \n",damp); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("damp= %18.15lf\n", damp); - if(wrFilebin) fprintf(fpSolPropsFileBin,"damp= %lf\n", damp); - - if(fscanf(fpSolProps, "nStar= %ld\n",&nStar) != 1) { - printf("Error reading nStar %ld \n",nStar); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nStar= %7ld\n", nStar); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nStar= %ld\n", nStar); - - if(fscanf(fpSolProps, "nAstroP= %hd\n",&nAstroP) != 1) { - printf("Error reading nAstroP %hd \n",nAstroP); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nAstroP= %7hd\n", nAstroP); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nAstroP= %hd\n", nAstroP); - - if(fscanf(fpSolProps, "nAstroPSolved= %hd\n",&nAstroPSolved) != 1) { - printf("Error reading nAstroPSolved %hd \n",nAstroPSolved); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nAstroPSolved= %hd\n", nAstroPSolved); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nAstroPSolved= %hd\n", nAstroPSolved); - - if(fscanf(fpSolProps, "nConstrLat= %ld\n",&nConstrLat) != 1) { - printf("Error reading nConstrLat %ld \n",nConstrLat); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nConstrLat= %5ld\n", nConstrLat); - if(wrFilebin){ - if(noConstr) fprintf(fpSolPropsFileBin,"nConstrLat= 0\n"); - else fprintf(fpSolPropsFileBin,"nConstrLat= %ld\n", nConstrLat); } - if(nConstrLat>0) + else { - constrLatId = (long *) calloc(nConstrLat, sizeof(long)); - for(i=0;i<nConstrLat-1;i++) { - if(fscanf(fpSolProps, "%ld ",&constrLatId[i]) != 1) { - printf("Error reading constrLatId[%d] %ld \n",i,constrLatId[i]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(debugMode) printf("constrLatId[%d]=%7ld ",i,constrLatId[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%ld ",constrLatId[i]); + fpSolProps = fopen(filenameSolProps, "r"); + if (!fpSolProps) + { + printf("Error while open %s\n", filenameSolProps); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); } - if(fscanf(fpSolProps, "%ld\n",&constrLatId[nConstrLat-1]) != 1) { - printf("Error reading constrLatId[nConstrLat-1] %ld \n", constrLatId[nConstrLat-1]); - MPI_Abort(MPI_COMM_WORLD,1); + + if (fscanf(fpSolProps, "sphereId= %ld\n", &sphereId) != 1) + { + printf("Error reading sphereId %ld \n", sphereId); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrLatId[nConstrLat-1]=%7ld\n",constrLatId[nConstrLat-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%ld\n",constrLatId[nConstrLat-1]); - - constrLatW = (double *) calloc(nConstrLat, sizeof(double)); - for(i=0;i<nConstrLat-1;i++) { - if(fscanf(fpSolProps, "%lf ",&constrLatW[i]) != 1) { - printf("Error reading constrLatW[%d] %lf \n",i,constrLatW[i]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(debugMode) printf("constrLatW[%d]=%18.15le ",i,constrLatW[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf ",constrLatW[i]); + printf("sphereId= %7ld\n", sphereId); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "sphereId= %ld\n", sphereId); + + if (fscanf(fpSolProps, "atol= %lf\n", &atol) != 1) + { + printf("Error reading atol %lf \n", atol); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); } - if(fscanf(fpSolProps, "%lf\n",&constrLatW[nConstrLat-1]) != 1) { - printf("Error reading constrLatW[nConstrLat-1] %lf \n", constrLatW[nConstrLat-1]); - MPI_Abort(MPI_COMM_WORLD,1); + if (aTol >= 0) + atol = aTol; + printf("atol= %18.15lf\n", atol); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "atol= %lf\n", atol); + + if (fscanf(fpSolProps, "btol= %lf\n", &btol) != 1) + { + printf("Error reading btol %lf \n", btol); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrLatW[nConstrLat-1]=%18.15lf\n",constrLatW[nConstrLat-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf\n",constrLatW[nConstrLat-1]); - } - - if(fscanf(fpSolProps, "nConstrLong= %ld\n",&nConstrLong) != 1) { - printf("Error reading nConstrLong %ld \n",nConstrLong); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nConstrLong= %5ld\n", nConstrLong); - if(wrFilebin){ - if(noConstr) fprintf(fpSolPropsFileBin,"nConstrLong= 0\n"); - else fprintf(fpSolPropsFileBin,"nConstrLong= %ld\n", nConstrLong); - } - if(nConstrLong>0) - { - constrLongId = (long *) calloc(nConstrLong, sizeof(long)); - for(i=0;i<nConstrLong-1;i++) { - if(fscanf(fpSolProps, "%ld ",&constrLongId[i]) != 1) { - printf("Error reading constrLongId[%d] %ld \n",i,constrLongId[i]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(debugMode) printf("constrLongId[%d]=%7ld ",i,constrLongId[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%ld ",constrLongId[i]); + printf("btol= %18.15lf\n", btol); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "btol= %lf\n", btol); + + if (fscanf(fpSolProps, "conlim= %lf\n", &conlim) != 1) + { + printf("Error reading conlim %lf \n", conlim); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); } - if(fscanf(fpSolProps, "%ld\n",&constrLongId[nConstrLong-1]) != 1) { - printf("Error reading constrLongId[nConstrLong-1] %ld \n", constrLongId[nConstrLong-1]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("conlim= %18.15le\n", conlim); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "conlim= %lf\n", conlim); + + if (fscanf(fpSolProps, "itnlim= %ld\n", &itnlim) != 1) + { + printf("Error reading itnlim %ld \n", itnlim); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrLongId[nConstrLong-1]=%7ld\n",constrLongId[nConstrLong-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%ld\n",constrLongId[nConstrLong-1]); - - constrLongW = (double *) calloc(nConstrLong, sizeof(double)); - for(i=0;i<nConstrLong-1;i++) { - if(fscanf(fpSolProps, "%lf ",&constrLongW[i]) != 1) { - printf("Error reading constrLongW[%d] %lf \n",i,constrLongW[i]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(debugMode) printf("constrLongW[%d]=%18.15le ",i,constrLongW[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf ",constrLongW[i]); + if (itnLimit > 0) + itnlim = itnLimit; + printf("itnlim= %7ld\n", itnlim); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "itnlim= %ld\n", itnlim); + + if (fscanf(fpSolProps, "damp= %lf\n", &damp) != 1) + { + printf("Error reading damp %lf \n", damp); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); } - if(fscanf(fpSolProps, "%lf\n",&constrLongW[nConstrLong-1]) != 1) { - printf("Error reading constrLongW[nConstrLong-1] %lf \n", constrLongW[nConstrLong-1]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("damp= %18.15lf\n", damp); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "damp= %lf\n", damp); + + if (fscanf(fpSolProps, "nStar= %ld\n", &nStar) != 1) + { + printf("Error reading nStar %ld \n", nStar); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrLongW[nConstrLong-1]=%18.15lf\n",constrLongW[nConstrLong-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf\n",constrLongW[nConstrLong-1]); - } - - if(fscanf(fpSolProps, "nConstrMuLat= %ld\n",&nConstrMuLat) != 1) { - printf("Error reading nConstrMuLat %ld \n",nConstrMuLat); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nConstrMuLat= %5ld\n", nConstrMuLat); - if(wrFilebin){ - if(noConstr) fprintf(fpSolPropsFileBin,"nConstrMuLat= 0\n"); - else fprintf(fpSolPropsFileBin,"nConstrMuLat= %ld\n", nConstrMuLat); - } - - if(nConstrMuLat>0) - { - constrMuLatId = (long *) calloc(nConstrMuLat, sizeof(long)); - for(i=0;i<nConstrMuLat-1;i++) { - if(fscanf(fpSolProps, "%ld ",&constrMuLatId[i]) != 1) { - printf("Error reading constrMuLatId[%d] %ld \n",i,constrMuLatId[i]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(debugMode) printf("constrMuLatId[%d]=%7ld ",i,constrMuLatId[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%ld ",constrMuLatId[i]); + printf("nStar= %7ld\n", nStar); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nStar= %ld\n", nStar); + + if (fscanf(fpSolProps, "nAstroP= %hd\n", &nAstroP) != 1) + { + printf("Error reading nAstroP %hd \n", nAstroP); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("nAstroP= %7hd\n", nAstroP); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nAstroP= %hd\n", nAstroP); + + if (fscanf(fpSolProps, "nAstroPSolved= %hd\n", &nAstroPSolved) != 1) + { + printf("Error reading nAstroPSolved %hd \n", nAstroPSolved); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); } - if(fscanf(fpSolProps, "%ld\n",&constrMuLatId[nConstrMuLat-1]) != 1) { - printf("Error reading constrMuLatId[nConstrMuLat-1] %ld \n", constrMuLatId[nConstrMuLat-1]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("nAstroPSolved= %hd\n", nAstroPSolved); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nAstroPSolved= %hd\n", nAstroPSolved); + + if (fscanf(fpSolProps, "nConstrLat= %ld\n", &nConstrLat) != 1) + { + printf("Error reading nConstrLat %ld \n", nConstrLat); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrMuLatId[nConstrMuLat-1]=%7ld\n",constrMuLatId[nConstrMuLat-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%ld\n",constrMuLatId[nConstrMuLat-1]); - - constrMuLatW = (double *) calloc(nConstrMuLat, sizeof(double)); - for(i=0;i<nConstrMuLat-1;i++) { - if(fscanf(fpSolProps, "%lf ",&constrMuLatW[i]) != 1) { - printf("Error reading constrMuLatW[%d] %lf \n",i,constrMuLatW[i]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("nConstrLat= %5ld\n", nConstrLat); + if (wrFilebin) + { + if (noConstr) + fprintf(fpSolPropsFileBin, "nConstrLat= 0\n"); + else + fprintf(fpSolPropsFileBin, "nConstrLat= %ld\n", nConstrLat); + } + if (nConstrLat > 0) + { + constrLatId = (long *)calloc(nConstrLat, sizeof(long)); + for (i = 0; i < nConstrLat - 1; i++) + { + if (fscanf(fpSolProps, "%ld ", &constrLatId[i]) != 1) + { + printf("Error reading constrLatId[%d] %ld \n", i, constrLatId[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrLatId[%d]=%7ld ", i, constrLatId[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%ld ", constrLatId[i]); + } + if (fscanf(fpSolProps, "%ld\n", &constrLatId[nConstrLat - 1]) != 1) + { + printf("Error reading constrLatId[nConstrLat-1] %ld \n", constrLatId[nConstrLat - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrLatId[nConstrLat-1]=%7ld\n", constrLatId[nConstrLat - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%ld\n", constrLatId[nConstrLat - 1]); + + constrLatW = (double *)calloc(nConstrLat, sizeof(double)); + for (i = 0; i < nConstrLat - 1; i++) + { + if (fscanf(fpSolProps, "%lf ", &constrLatW[i]) != 1) + { + printf("Error reading constrLatW[%d] %lf \n", i, constrLatW[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrLatW[%d]=%18.15le ", i, constrLatW[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf ", constrLatW[i]); + } + if (fscanf(fpSolProps, "%lf\n", &constrLatW[nConstrLat - 1]) != 1) + { + printf("Error reading constrLatW[nConstrLat-1] %lf \n", constrLatW[nConstrLat - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrMuLatW[%d]=%18.15le ",i,constrMuLatW[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf ",constrMuLatW[i]); + if (debugMode) + printf("constrLatW[nConstrLat-1]=%18.15lf\n", constrLatW[nConstrLat - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf\n", constrLatW[nConstrLat - 1]); } - if(fscanf(fpSolProps, "%lf\n",&constrMuLatW[nConstrMuLat-1]) != 1) { - printf("Error reading constrMuLatW[nConstrMuLat-1] %lf \n", constrMuLatW[nConstrMuLat-1]); - MPI_Abort(MPI_COMM_WORLD,1); + + if (fscanf(fpSolProps, "nConstrLong= %ld\n", &nConstrLong) != 1) + { + printf("Error reading nConstrLong %ld \n", nConstrLong); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrMuLatW[nConstrMuLat-1]=%18.15lf\n",constrMuLatW[nConstrMuLat-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf\n",constrMuLatW[nConstrMuLat-1]); - - } - - if(fscanf(fpSolProps, "nConstrMuLong= %ld\n",&nConstrMuLong) != 1) { - printf("Error reading nConstrMuLong %ld \n",nConstrMuLong); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nConstrMuLong= %5ld\n", nConstrMuLong); - if(wrFilebin){ - if(noConstr) fprintf(fpSolPropsFileBin,"nConstrMuLong= 0\n"); - else fprintf(fpSolPropsFileBin,"nConstrMuLong= %ld\n", nConstrMuLong); - } - if(nConstrMuLong>0) - { - constrMuLongId = (long *) calloc(nConstrMuLong, sizeof(long)); - for(i=0;i<nConstrMuLong-1;i++) { - if(fscanf(fpSolProps, "%ld ",&constrMuLongId[i]) != 1) { - printf("Error reading constrMuLongId[%d] %ld \n",i,constrMuLongId[i]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("nConstrLong= %5ld\n", nConstrLong); + if (wrFilebin) + { + if (noConstr) + fprintf(fpSolPropsFileBin, "nConstrLong= 0\n"); + else + fprintf(fpSolPropsFileBin, "nConstrLong= %ld\n", nConstrLong); + } + if (nConstrLong > 0) + { + constrLongId = (long *)calloc(nConstrLong, sizeof(long)); + for (i = 0; i < nConstrLong - 1; i++) + { + if (fscanf(fpSolProps, "%ld ", &constrLongId[i]) != 1) + { + printf("Error reading constrLongId[%d] %ld \n", i, constrLongId[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrLongId[%d]=%7ld ", i, constrLongId[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%ld ", constrLongId[i]); + } + if (fscanf(fpSolProps, "%ld\n", &constrLongId[nConstrLong - 1]) != 1) + { + printf("Error reading constrLongId[nConstrLong-1] %ld \n", constrLongId[nConstrLong - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrLongId[nConstrLong-1]=%7ld\n", constrLongId[nConstrLong - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%ld\n", constrLongId[nConstrLong - 1]); + + constrLongW = (double *)calloc(nConstrLong, sizeof(double)); + for (i = 0; i < nConstrLong - 1; i++) + { + if (fscanf(fpSolProps, "%lf ", &constrLongW[i]) != 1) + { + printf("Error reading constrLongW[%d] %lf \n", i, constrLongW[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrLongW[%d]=%18.15le ", i, constrLongW[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf ", constrLongW[i]); + } + if (fscanf(fpSolProps, "%lf\n", &constrLongW[nConstrLong - 1]) != 1) + { + printf("Error reading constrLongW[nConstrLong-1] %lf \n", constrLongW[nConstrLong - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrMuLongId[%d]=%7ld ",i,constrMuLongId[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%7ld ",constrMuLongId[i]); + if (debugMode) + printf("constrLongW[nConstrLong-1]=%18.15lf\n", constrLongW[nConstrLong - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf\n", constrLongW[nConstrLong - 1]); } - if(fscanf(fpSolProps, "%ld\n",&constrMuLongId[nConstrMuLong-1]) != 1) { - printf("Error reading constrMuLongId[nConstrMuLong-1] %ld \n", constrMuLongId[nConstrMuLong-1]); - MPI_Abort(MPI_COMM_WORLD,1); + + if (fscanf(fpSolProps, "nConstrMuLat= %ld\n", &nConstrMuLat) != 1) + { + printf("Error reading nConstrMuLat %ld \n", nConstrMuLat); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrMuLongId[nConstrMuLong-1]=%7ld\n",constrMuLongId[nConstrMuLong-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%ld\n",constrMuLongId[nConstrMuLong-1]); - - constrMuLongW = (double *) calloc(nConstrMuLong, sizeof(double)); - for(i=0;i<nConstrMuLong-1;i++) { - if(fscanf(fpSolProps, "%lf ",&constrMuLongW[i]) != 1) { - printf("Error reading constrMuLongW[%d] %lf \n",i,constrMuLongW[i]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("nConstrMuLat= %5ld\n", nConstrMuLat); + if (wrFilebin) + { + if (noConstr) + fprintf(fpSolPropsFileBin, "nConstrMuLat= 0\n"); + else + fprintf(fpSolPropsFileBin, "nConstrMuLat= %ld\n", nConstrMuLat); + } + + if (nConstrMuLat > 0) + { + constrMuLatId = (long *)calloc(nConstrMuLat, sizeof(long)); + for (i = 0; i < nConstrMuLat - 1; i++) + { + if (fscanf(fpSolProps, "%ld ", &constrMuLatId[i]) != 1) + { + printf("Error reading constrMuLatId[%d] %ld \n", i, constrMuLatId[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrMuLatId[%d]=%7ld ", i, constrMuLatId[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%ld ", constrMuLatId[i]); + } + if (fscanf(fpSolProps, "%ld\n", &constrMuLatId[nConstrMuLat - 1]) != 1) + { + printf("Error reading constrMuLatId[nConstrMuLat-1] %ld \n", constrMuLatId[nConstrMuLat - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrMuLatId[nConstrMuLat-1]=%7ld\n", constrMuLatId[nConstrMuLat - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%ld\n", constrMuLatId[nConstrMuLat - 1]); + + constrMuLatW = (double *)calloc(nConstrMuLat, sizeof(double)); + for (i = 0; i < nConstrMuLat - 1; i++) + { + if (fscanf(fpSolProps, "%lf ", &constrMuLatW[i]) != 1) + { + printf("Error reading constrMuLatW[%d] %lf \n", i, constrMuLatW[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrMuLatW[%d]=%18.15le ", i, constrMuLatW[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf ", constrMuLatW[i]); + } + if (fscanf(fpSolProps, "%lf\n", &constrMuLatW[nConstrMuLat - 1]) != 1) + { + printf("Error reading constrMuLatW[nConstrMuLat-1] %lf \n", constrMuLatW[nConstrMuLat - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrMuLongW[%d]=%18.15le ",i,constrMuLongW[i]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf ",constrMuLongW[i]); + if (debugMode) + printf("constrMuLatW[nConstrMuLat-1]=%18.15lf\n", constrMuLatW[nConstrMuLat - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf\n", constrMuLatW[nConstrMuLat - 1]); } - if(fscanf(fpSolProps, "%lf\n",&constrMuLongW[nConstrMuLong-1]) != 1) { - printf("Error reading constrMuLongW[nConstrMuLong-1] %lf \n", constrMuLongW[nConstrMuLong-1]); - MPI_Abort(MPI_COMM_WORLD,1); + + if (fscanf(fpSolProps, "nConstrMuLong= %ld\n", &nConstrMuLong) != 1) + { + printf("Error reading nConstrMuLong %ld \n", nConstrMuLong); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(debugMode) printf("constrMuLongW[nConstrMuLong-1]=%18.15lf\n",constrMuLongW[nConstrMuLong-1]); - if(wrFilebin && !noConstr) fprintf(fpSolPropsFileBin,"%lf\n",constrMuLongW[nConstrMuLong-1]); - } - - if(fscanf(fpSolProps, "nDegFreedomAtt= %ld\n",&nDegFreedomAtt) != 1) { - printf("Error reading nDegFreedomAtt %ld \n",nDegFreedomAtt); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroAtt) nDegFreedomAtt=0; - printf("nDegFreedomAtt= %7ld\n", nDegFreedomAtt); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nDegFreedomAtt= %ld\n", nDegFreedomAtt); - - if(fscanf(fpSolProps, "nAttAxes= %hd\n",&nAttAxes) != 1) { - printf("Error reading nAttAxes %hd \n",nAttAxes); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroAtt) nAttAxes=0; - printf("nAttAxes= %7hd\n", nAttAxes); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nAttAxes= %hd\n", nAttAxes); - - if(fscanf(fpSolProps, "nFoVs= %d\n",&instrConst[0]) != 1) { - printf("Error reading nFoVs %d \n",instrConst[0]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroInstr) instrConst[0]=0; - // instrConst[0] must be 0 or 1 because nFoVs = 2 for Gaia and nFoVs=1+instrConst[0] - if(instrConst[0]<0 || instrConst[0]>1){ - printf("Execution aborted with invalid nFovs=%d\n",instrConst[0]+1); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - - } - printf("nFovs= %7d ", instrConst[0]+1); - printf("(instrConst[0])= %7d\n", instrConst[0]); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nFoVs= %d\n", instrConst[0]); - - if(fscanf(fpSolProps, "nCCDs= %d\n",&instrConst[1]) != 1) { - printf("Error reading nCCDs %d \n",instrConst[1]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroInstr) instrConst[1]=0; - printf("nCCDs= %7d\n", instrConst[1]); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nCCDs= %d\n", instrConst[1]); - - if(fscanf(fpSolProps, "nPixelColumns= %d\n",&instrConst[2]) != 1) { - printf("Error reading nPixelColumns %d \n",instrConst[2]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroInstr) instrConst[2]=0; - printf("nPixelColumns= %7d\n", instrConst[2]); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nPixelColumns= %d\n", instrConst[2]); - - if(fscanf(fpSolProps, "nTimeIntervals= %d\n",&instrConst[3]) != 1) { - printf("Error reading nTimeIntervals %d \n",instrConst[3]); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroInstr) instrConst[3]=0; - printf("nTimeIntervals= %7d\n", instrConst[3]); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nTimeIntervals= %d\n", instrConst[3]); - - if(fscanf(fpSolProps, "nInstrP= %hd\n",&nInstrP) != 1) { - printf("Error reading nInstrP %hd \n",nInstrP); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroInstr) nInstrP=0; - printf("nInstrP= %7hd\n", nInstrP); - if(nInstrP!=0 && nInstrP !=6){ - printf("Execution aborted with invalid nInstrP\n"); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(wrFilebin) fprintf(fpSolPropsFileBin,"nInstrP= %hd\n", nInstrP); - if(fscanf(fpSolProps, "nInstrPSolved= %hd\n",&nInstrPSolved) != 1) - { - printf("Error reading nInstrPSolved %hd \n",nInstrPSolved); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nInstrPSolved= %7hd\n", nInstrPSolved); - - if(nInstrPSolved<0 || nInstrPSolved >6){ - printf("Execution aborted with invalid nInstrPSolved\n"); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(wrFilebin) fprintf(fpSolPropsFileBin,"nInstrPSolved= %hd\n", nInstrPSolved); - - if(fscanf(fpSolProps, "lsInstrFlag= %d\n",&lsInstrFlag) != 1) - { - printf("Error reading lsInstrFlag %d \n",lsInstrFlag); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("lsInstrFlag= %7d\n", lsInstrFlag); - - if(lsInstrFlag<0 || lsInstrFlag >1){ - printf("Execution aborted with invalid lsInstrFlag\n"); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(wrFilebin) fprintf(fpSolPropsFileBin,"lsInstrFlag= %hd\n", lsInstrFlag); - if(fscanf(fpSolProps, "ssInstrFlag= %d\n",&ssInstrFlag) != 1) - { - printf("Error reading ssInstrFlag %d \n",ssInstrFlag); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("ssInstrFlag= %7d\n", ssInstrFlag); - - if(ssInstrFlag<0 || ssInstrFlag >1){ - printf("Execution aborted with invalid ssInstrFlag\n"); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(wrFilebin) fprintf(fpSolPropsFileBin,"ssInstrFlag= %hd\n", ssInstrFlag); - if(fscanf(fpSolProps, "nuInstrFlag= %d\n",&nuInstrFlag) != 1) - { - printf("Error reading nuInstrFlag %d \n",nuInstrFlag); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nuInstrFlag= %7d\n", nuInstrFlag); - - if(nuInstrFlag<0 || nuInstrFlag >1){ - printf("Execution aborted with invalid lsInstrFlag\n"); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(wrFilebin) fprintf(fpSolPropsFileBin,"nuInstrFlag= %hd\n", nuInstrFlag); - if(fscanf(fpSolProps, "maInstrFlag= %d\n",&maInstrFlag) != 1) - { - printf("Error reading maInstrFlag %d \n",maInstrFlag); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("maInstrFlag= %7d\n", maInstrFlag); - - if(maInstrFlag<0 || maInstrFlag >1){ - printf("Execution aborted with invalid maInstrFlag\n"); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(wrFilebin) fprintf(fpSolPropsFileBin,"maInstrFlag= %hd\n", maInstrFlag); + printf("nConstrMuLong= %5ld\n", nConstrMuLong); + if (wrFilebin) + { + if (noConstr) + fprintf(fpSolPropsFileBin, "nConstrMuLong= 0\n"); + else + fprintf(fpSolPropsFileBin, "nConstrMuLong= %ld\n", nConstrMuLong); + } + if (nConstrMuLong > 0) + { + constrMuLongId = (long *)calloc(nConstrMuLong, sizeof(long)); + for (i = 0; i < nConstrMuLong - 1; i++) + { + if (fscanf(fpSolProps, "%ld ", &constrMuLongId[i]) != 1) + { + printf("Error reading constrMuLongId[%d] %ld \n", i, constrMuLongId[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrMuLongId[%d]=%7ld ", i, constrMuLongId[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%7ld ", constrMuLongId[i]); + } + if (fscanf(fpSolProps, "%ld\n", &constrMuLongId[nConstrMuLong - 1]) != 1) + { + printf("Error reading constrMuLongId[nConstrMuLong-1] %ld \n", constrMuLongId[nConstrMuLong - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrMuLongId[nConstrMuLong-1]=%7ld\n", constrMuLongId[nConstrMuLong - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%ld\n", constrMuLongId[nConstrMuLong - 1]); - if(nInstrPSolved != maInstrFlag+nuInstrFlag+ssInstrFlag+3*lsInstrFlag){ - printf("Execution aborted invalid nInstrPSolved=%d. It should be =%d\n",nInstrPSolved,maInstrFlag+nuInstrFlag+ssInstrFlag+3*lsInstrFlag); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - - } - - if(fscanf(fpSolProps, "nOfInstrConstr= %d\n",&nOfInstrConstr) != 1) - { - printf("Error reading nOfInstrConstr %d \n",nOfInstrConstr); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nOfInstrConstr= %7d\n", nOfInstrConstr); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nOfInstrConstr= %d\n", nOfInstrConstr); - - if(fscanf(fpSolProps, "nElemIC= %d\n",&nElemIC) != 1) + constrMuLongW = (double *)calloc(nConstrMuLong, sizeof(double)); + for (i = 0; i < nConstrMuLong - 1; i++) + { + if (fscanf(fpSolProps, "%lf ", &constrMuLongW[i]) != 1) + { + printf("Error reading constrMuLongW[%d] %lf \n", i, constrMuLongW[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrMuLongW[%d]=%18.15le ", i, constrMuLongW[i]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf ", constrMuLongW[i]); + } + if (fscanf(fpSolProps, "%lf\n", &constrMuLongW[nConstrMuLong - 1]) != 1) + { + printf("Error reading constrMuLongW[nConstrMuLong-1] %lf \n", constrMuLongW[nConstrMuLong - 1]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (debugMode) + printf("constrMuLongW[nConstrMuLong-1]=%18.15lf\n", constrMuLongW[nConstrMuLong - 1]); + if (wrFilebin && !noConstr) + fprintf(fpSolPropsFileBin, "%lf\n", constrMuLongW[nConstrMuLong - 1]); + } + + if (fscanf(fpSolProps, "nDegFreedomAtt= %ld\n", &nDegFreedomAtt) != 1) + { + printf("Error reading nDegFreedomAtt %ld \n", nDegFreedomAtt); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroAtt) + nDegFreedomAtt = 0; + printf("nDegFreedomAtt= %7ld\n", nDegFreedomAtt); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nDegFreedomAtt= %ld\n", nDegFreedomAtt); + + if (fscanf(fpSolProps, "nAttAxes= %hd\n", &nAttAxes) != 1) + { + printf("Error reading nAttAxes %hd \n", nAttAxes); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroAtt) + nAttAxes = 0; + printf("nAttAxes= %7hd\n", nAttAxes); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nAttAxes= %hd\n", nAttAxes); + + if (fscanf(fpSolProps, "nFoVs= %d\n", &instrConst[0]) != 1) + { + printf("Error reading nFoVs %d \n", instrConst[0]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroInstr) + instrConst[0] = 0; + // instrConst[0] must be 0 or 1 because nFoVs = 2 for Gaia and nFoVs=1+instrConst[0] + if (instrConst[0] < 0 || instrConst[0] > 1) + { + printf("Execution aborted with invalid nFovs=%d\n", instrConst[0] + 1); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("nFovs= %7d ", instrConst[0] + 1); + printf("(instrConst[0])= %7d\n", instrConst[0]); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nFoVs= %d\n", instrConst[0]); + + if (fscanf(fpSolProps, "nCCDs= %d\n", &instrConst[1]) != 1) + { + printf("Error reading nCCDs %d \n", instrConst[1]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroInstr) + instrConst[1] = 0; + printf("nCCDs= %7d\n", instrConst[1]); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nCCDs= %d\n", instrConst[1]); + + if (fscanf(fpSolProps, "nPixelColumns= %d\n", &instrConst[2]) != 1) + { + printf("Error reading nPixelColumns %d \n", instrConst[2]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroInstr) + instrConst[2] = 0; + printf("nPixelColumns= %7d\n", instrConst[2]); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nPixelColumns= %d\n", instrConst[2]); + + if (fscanf(fpSolProps, "nTimeIntervals= %d\n", &instrConst[3]) != 1) + { + printf("Error reading nTimeIntervals %d \n", instrConst[3]); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroInstr) + instrConst[3] = 0; + printf("nTimeIntervals= %7d\n", instrConst[3]); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nTimeIntervals= %d\n", instrConst[3]); + + if (fscanf(fpSolProps, "nInstrP= %hd\n", &nInstrP) != 1) + { + printf("Error reading nInstrP %hd \n", nInstrP); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroInstr) + nInstrP = 0; + printf("nInstrP= %7hd\n", nInstrP); + if (nInstrP != 0 && nInstrP != 6) + { + printf("Execution aborted with invalid nInstrP\n"); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nInstrP= %hd\n", nInstrP); + if (fscanf(fpSolProps, "nInstrPSolved= %hd\n", &nInstrPSolved) != 1) + { + printf("Error reading nInstrPSolved %hd \n", nInstrPSolved); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("nInstrPSolved= %7hd\n", nInstrPSolved); + + if (nInstrPSolved < 0 || nInstrPSolved > 6) + { + printf("Execution aborted with invalid nInstrPSolved\n"); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nInstrPSolved= %hd\n", nInstrPSolved); + + if (fscanf(fpSolProps, "lsInstrFlag= %d\n", &lsInstrFlag) != 1) + { + printf("Error reading lsInstrFlag %d \n", lsInstrFlag); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("lsInstrFlag= %7d\n", lsInstrFlag); + + if (lsInstrFlag < 0 || lsInstrFlag > 1) + { + printf("Execution aborted with invalid lsInstrFlag\n"); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (wrFilebin) + fprintf(fpSolPropsFileBin, "lsInstrFlag= %hd\n", lsInstrFlag); + if (fscanf(fpSolProps, "ssInstrFlag= %d\n", &ssInstrFlag) != 1) + { + printf("Error reading ssInstrFlag %d \n", ssInstrFlag); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("ssInstrFlag= %7d\n", ssInstrFlag); + + if (ssInstrFlag < 0 || ssInstrFlag > 1) + { + printf("Execution aborted with invalid ssInstrFlag\n"); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (wrFilebin) + fprintf(fpSolPropsFileBin, "ssInstrFlag= %hd\n", ssInstrFlag); + if (fscanf(fpSolProps, "nuInstrFlag= %d\n", &nuInstrFlag) != 1) + { + printf("Error reading nuInstrFlag %d \n", nuInstrFlag); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("nuInstrFlag= %7d\n", nuInstrFlag); + + if (nuInstrFlag < 0 || nuInstrFlag > 1) + { + printf("Execution aborted with invalid lsInstrFlag\n"); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nuInstrFlag= %hd\n", nuInstrFlag); + if (fscanf(fpSolProps, "maInstrFlag= %d\n", &maInstrFlag) != 1) + { + printf("Error reading maInstrFlag %d \n", maInstrFlag); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("maInstrFlag= %7d\n", maInstrFlag); + + if (maInstrFlag < 0 || maInstrFlag > 1) + { + printf("Execution aborted with invalid maInstrFlag\n"); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (wrFilebin) + fprintf(fpSolPropsFileBin, "maInstrFlag= %hd\n", maInstrFlag); + + if (nInstrPSolved != maInstrFlag + nuInstrFlag + ssInstrFlag + 3 * lsInstrFlag) + { + printf("Execution aborted invalid nInstrPSolved=%d. It should be =%d\n", nInstrPSolved, maInstrFlag + nuInstrFlag + ssInstrFlag + 3 * lsInstrFlag); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + + if (fscanf(fpSolProps, "nOfInstrConstr= %d\n", &nOfInstrConstr) != 1) + { + printf("Error reading nOfInstrConstr %d \n", nOfInstrConstr); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("nOfInstrConstr= %7d\n", nOfInstrConstr); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nOfInstrConstr= %d\n", nOfInstrConstr); + + if (fscanf(fpSolProps, "nElemIC= %d\n", &nElemIC) != 1) + { + printf("Error reading nElemIC %d \n", nElemIC); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("nElemIC= %7d\n", nElemIC); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nElemIC= %d\n", nElemIC); + + if (fscanf(fpSolProps, "nGlobP= %hd\n", &nGlobP) != 1) + { + printf("Error reading nGlobP %hd \n", nGlobP); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + if (zeroGlob) + nGlobP = 0; + printf("nGlobP= %7hd\n", nGlobP); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nGlobP= %hd\n", nGlobP); + + if (fscanf(fpSolProps, "nObs= %ld\n", &nobs) != 1) + { + printf("Error reading nObs %ld \n", nobs); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); + } + printf("nObs= %10ld\n", nobs); + if (wrFilebin) + fprintf(fpSolPropsFileBin, "nObs= %ld\n", nobs); + + fclose(fpSolProps); + if (wrFilebin) + fclose(fpSolPropsFileBin); + } //if (autoRun) else + } + + endTime = MPI_Wtime(); + if ((nDegFreedomAtt == 0 && nAttAxes > 0) || (nDegFreedomAtt > 0 && nAttAxes == 0)) + { + if (myid == 0) { - printf("Error reading nElemIC %d \n",nElemIC); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - printf("nElemIC= %7d\n", nElemIC); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nElemIC= %d\n", nElemIC); - - - if(fscanf(fpSolProps, "nGlobP= %hd\n",&nGlobP) != 1) { - printf("Error reading nGlobP %hd \n",nGlobP); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); - } - if(zeroGlob) nGlobP=0; - printf("nGlobP= %7hd\n", nGlobP); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nGlobP= %hd\n", nGlobP); - - if(fscanf(fpSolProps, "nObs= %ld\n",&nobs) != 1) { - printf("Error reading nObs %ld \n",nobs); - MPI_Abort(MPI_COMM_WORLD,1); + printf("inconsistent values for nDegFreedomAtt=%ld and nAttaxes=%d\n", nDegFreedomAtt, nAttAxes); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - printf("nObs= %10ld\n", nobs); - if(wrFilebin) fprintf(fpSolPropsFileBin,"nObs= %ld\n", nobs); - - fclose(fpSolProps); - if(wrFilebin) fclose(fpSolPropsFileBin); - }//if (autoRun) else - } - - endTime=MPI_Wtime(); - if((nDegFreedomAtt==0 && nAttAxes>0) || (nDegFreedomAtt>0 && nAttAxes==0) ){ - if(myid==0){ - printf("inconsistent values for nDegFreedomAtt=%ld and nAttaxes=%d\n",nDegFreedomAtt,nAttAxes); - MPI_Abort(MPI_COMM_WORLD, 1); - exit(EXIT_FAILURE); - } } - - if(myid==0) printf("Time to read initial parameters =%f sec.\n",endTime-startTime); + + if (myid == 0) + printf("Time to read initial parameters =%f sec.\n", endTime - startTime); // Start section for parameter broadcast - MPI_Bcast( &atol, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast( &btol, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast( &conlim, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast( &damp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast( &nAstroP, 1, MPI_SHORT, 0, MPI_COMM_WORLD); - MPI_Bcast( &nAstroPSolved, 1, MPI_SHORT, 0, MPI_COMM_WORLD); - MPI_Bcast( &nInstrP, 1, MPI_SHORT, 0, MPI_COMM_WORLD); - MPI_Bcast( &nInstrPSolved, 1, MPI_SHORT, 0, MPI_COMM_WORLD); - MPI_Bcast( &lsInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &ssInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &nuInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &maInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &nElemIC, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &nOfInstrConstr, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast( &nGlobP, 1, MPI_SHORT, 0, MPI_COMM_WORLD); - MPI_Bcast( &itnlim, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( &nStar, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( &nDegFreedomAtt, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( &nAttAxes, 1, MPI_SHORT, 0, MPI_COMM_WORLD); - MPI_Bcast( &instrSetUp, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( instrConst, DEFAULT_NINSTRINDEXES , MPI_INT, 0, MPI_COMM_WORLD); // errore - MPI_Bcast( &nobs, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( &nConstrLat, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( &nConstrLong, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( &nConstrMuLat, 1, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( &nConstrMuLong, 1, MPI_LONG, 0, MPI_COMM_WORLD); - if(myid !=0) - { - constrLatId=(long *) calloc(nConstrLat , sizeof(long)); - constrLatW=(double *) calloc(nConstrLat , sizeof(double)); - constrLongId=(long *) calloc(nConstrLong , sizeof(long)); - constrLongW=(double *) calloc(nConstrLong , sizeof(double)); - constrMuLatId=(long *) calloc(nConstrMuLat , sizeof(long)); - constrMuLatW=(double *) calloc(nConstrMuLat , sizeof(double)); - constrMuLongId=(long *) calloc(nConstrMuLong , sizeof(long)); - constrMuLongW=(double *) calloc(nConstrMuLong , sizeof(double)); - } - MPI_Bcast( constrLatId, nConstrLat, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( constrLatW, nConstrLat, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast( constrLongId, nConstrLong, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( constrLongW, nConstrLong, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast( constrMuLatId, nConstrMuLat, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( constrMuLatW, nConstrMuLat, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast( constrMuLongId, nConstrMuLong, MPI_LONG, 0, MPI_COMM_WORLD); - MPI_Bcast( constrMuLongW, nConstrMuLong, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if(nInstrPSolved==0) - zeroInstr=1; + MPI_Bcast(&atol, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&btol, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&conlim, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&damp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&nAstroP, 1, MPI_SHORT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nAstroPSolved, 1, MPI_SHORT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nInstrP, 1, MPI_SHORT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nInstrPSolved, 1, MPI_SHORT, 0, MPI_COMM_WORLD); + MPI_Bcast(&lsInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&ssInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nuInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&maInstrFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nElemIC, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nOfInstrConstr, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nGlobP, 1, MPI_SHORT, 0, MPI_COMM_WORLD); + MPI_Bcast(&itnlim, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&nStar, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&nDegFreedomAtt, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&nAttAxes, 1, MPI_SHORT, 0, MPI_COMM_WORLD); + MPI_Bcast(&instrSetUp, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(instrConst, DEFAULT_NINSTRINDEXES, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nobs, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&nConstrLat, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&nConstrLong, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&nConstrMuLat, 1, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&nConstrMuLong, 1, MPI_LONG, 0, MPI_COMM_WORLD); + if (myid != 0) + { + constrLatId = (long *)calloc(nConstrLat, sizeof(long)); + constrLatW = (double *)calloc(nConstrLat, sizeof(double)); + constrLongId = (long *)calloc(nConstrLong, sizeof(long)); + constrLongW = (double *)calloc(nConstrLong, sizeof(double)); + constrMuLatId = (long *)calloc(nConstrMuLat, sizeof(long)); + constrMuLatW = (double *)calloc(nConstrMuLat, sizeof(double)); + constrMuLongId = (long *)calloc(nConstrMuLong, sizeof(long)); + constrMuLongW = (double *)calloc(nConstrMuLong, sizeof(double)); + } + MPI_Bcast(constrLatId, nConstrLat, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(constrLatW, nConstrLat, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(constrLongId, nConstrLong, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(constrLongW, nConstrLong, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(constrMuLatId, nConstrMuLat, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(constrMuLatW, nConstrMuLat, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(constrMuLatW, nConstrMuLat, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(constrMuLongId, nConstrMuLong, MPI_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(constrMuLongW, nConstrMuLong, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if (nInstrPSolved == 0) + zeroInstr = 1; /////////// Multiplicity of matrixIndex - + int multMI; - - if(nAstroPSolved) - multMI=2; - else{ - multMI=1; - extConstraint=0; - barConstraint=0; + + if (nAstroPSolved) + multMI = 2; + else + { + multMI = 1; + extConstraint = 0; + barConstraint = 0; } nAstroParam = nStar * nAstroPSolved; nAttParam = nDegFreedomAtt * nAttAxes; - if(nDegFreedomAtt<4) nAttParAxis=nDegFreedomAtt; - if(nDegFreedomAtt) nAttP = nAttAxes * nAttParAxis; - long nFoVs=1+instrConst[0]; - long nCCDs=instrConst[1]; - long nPixelColumns=instrConst[2]; - long nTimeIntervals=instrConst[3]; + if (nDegFreedomAtt < 4) + nAttParAxis = nDegFreedomAtt; + if (nDegFreedomAtt) + nAttP = nAttAxes * nAttParAxis; + long nFoVs = 1 + instrConst[0]; + long nCCDs = instrConst[1]; + long nPixelColumns = instrConst[2]; + long nTimeIntervals = instrConst[3]; // tot. instr. param. = nCCDs (Cmag) + nFoVs*nCCDs (Cnu) + nCCDs*nPixelColumns (delta_eta) + 3*nFoVs*nCCDs*nTimeIntervals (Delta_eta) + nCCDs*nPixelColumns (delta_zeta) + 3*nFoVs*nCCDs*nTimeIntervals (Delta_zeta) // added flags switch on and off the appropriate kind of parameters - nInstrParam = maInstrFlag*nCCDs+nuInstrFlag*nFoVs*nCCDs+ssInstrFlag*2*nCCDs*nPixelColumns+lsInstrFlag*2*3*nFoVs*nCCDs*nTimeIntervals; - nInstrParamTot = nCCDs+ nFoVs*nCCDs+ 2*nCCDs*nPixelColumns+2*3*nFoVs*nCCDs*nTimeIntervals; + nInstrParam = maInstrFlag * nCCDs + nuInstrFlag * nFoVs * nCCDs + ssInstrFlag * 2 * nCCDs * nPixelColumns + lsInstrFlag * 2 * 3 * nFoVs * nCCDs * nTimeIntervals; + nInstrParamTot = nCCDs + nFoVs * nCCDs + 2 * nCCDs * nPixelColumns + 2 * 3 * nFoVs * nCCDs * nTimeIntervals; nGlobalParam = nGlobP; - - if(nElemIC<0 || nOfInstrConstr <0){ - - - nOfInstrConstrLSAL = lsInstrFlag*nTimeIntervals; - nElemICLSAL = nFoVs*nCCDs; - nOfInstrConstrLSAC = lsInstrFlag*nFoVs*nTimeIntervals; + + if (nElemIC < 0 || nOfInstrConstr < 0) + { + nOfInstrConstrLSAL = lsInstrFlag * nTimeIntervals; + nElemICLSAL = nFoVs * nCCDs; + nOfInstrConstrLSAC = lsInstrFlag * nFoVs * nTimeIntervals; nElemICLSAC = nCCDs; - nOfInstrConstrSS = lsInstrFlag*ssInstrFlag*2*nCCDs*3; // the factor 2 comes from the AL and AC constraint equations + nOfInstrConstrSS = lsInstrFlag * ssInstrFlag * 2 * nCCDs * 3; // the factor 2 comes from the AL and AC constraint equations nElemICSS = nPixelColumns; nOfInstrConstr = nOfInstrConstrLSAL + nOfInstrConstrLSAC + nOfInstrConstrSS; - nElemIC = nOfInstrConstrLSAL*nElemICLSAL + nOfInstrConstrLSAC*nElemICLSAC + nOfInstrConstrSS*nElemICSS; - + nElemIC = nOfInstrConstrLSAL * nElemICLSAL + nOfInstrConstrLSAC * nElemICLSAC + nOfInstrConstrSS * nElemICSS; } - // Map the solved astrometric parameters, putting their indeces into an array of size nAstroPSolved // astroCoeff[0] -> parallax // astroCoeff[1] -> alpha @@ -1192,47 +1400,52 @@ int main(int argc, char **argv) { // nAstroPSolved=3 => parallax, alpha, delta, and the array is mapAstroP=[0,1,2] // nAstroPSolved=4 => alpha, delta, mu alpha, mu delta and the array is mapAstroP=[1,2,3,4] // nAstroPSolved=5 => parallax, alpha, delta, mu alpha, mu delta and the array is mapAstroP=[0,1,2,3,4] - - int LatPos=-1, LongPos=-1,MuLatPos=-1, MuLongPos=-1; - - if(nAstroPSolved) + + int LatPos = -1, LongPos = -1, MuLatPos = -1, MuLongPos = -1; + + if (nAstroPSolved) { - mapAstroP=(int *) calloc(nAstroPSolved, sizeof(int)); - switch(nAstroPSolved) { + mapAstroP = (int *)calloc(nAstroPSolved, sizeof(int)); + switch (nAstroPSolved) + { case 2: mapAstroP[0] = 1; mapAstroP[1] = 2; - LongPos=0; - LatPos=1; - MuLongPos=-1; - MuLatPos=-1; - nConstrMuLat=0; - nConstrMuLong=0; - if(extConstraint) nEqExtConstr=3; - if(barConstraint) nEqBarConstr=3; + LongPos = 0; + LatPos = 1; + MuLongPos = -1; + MuLatPos = -1; + nConstrMuLat = 0; + nConstrMuLong = 0; + if (extConstraint) + nEqExtConstr = 3; + if (barConstraint) + nEqBarConstr = 3; break; case 3: mapAstroP[0] = 0; mapAstroP[1] = 1; mapAstroP[2] = 2; - LongPos=1; - LatPos=2; - MuLongPos=-1; - MuLatPos=-1; - nConstrMuLat=0; - nConstrMuLong=0; - if(extConstraint) nEqExtConstr=3; - if(barConstraint) nEqBarConstr=3; - break; + LongPos = 1; + LatPos = 2; + MuLongPos = -1; + MuLatPos = -1; + nConstrMuLat = 0; + nConstrMuLong = 0; + if (extConstraint) + nEqExtConstr = 3; + if (barConstraint) + nEqBarConstr = 3; + break; case 4: mapAstroP[0] = 1; mapAstroP[1] = 2; mapAstroP[2] = 3; mapAstroP[3] = 4; - LongPos=0; - LatPos=1; - MuLongPos=2; - MuLatPos=3; + LongPos = 0; + LatPos = 1; + MuLongPos = 2; + MuLatPos = 3; break; case 5: mapAstroP[0] = 0; @@ -1240,861 +1453,959 @@ int main(int argc, char **argv) { mapAstroP[2] = 2; mapAstroP[3] = 3; mapAstroP[4] = 4; - LongPos=1; - LatPos=2; - MuLongPos=3; - MuLatPos=4; + LongPos = 1; + LatPos = 2; + MuLongPos = 3; + MuLatPos = 4; break; default: - if(myid==0) { + if (myid == 0) + { printf("nAstroPSolved=%d, invalid value. Aborting.\n", nAstroPSolved); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } } } // End map - /////////////////////// end broadcast section - + // Initialize the values needed to dimension the vectors nConstr = nConstrLong + nConstrLat + nConstrMuLong + nConstrMuLat; // number of constraints to be generated - - nObsxStar=nobs/nStar; - nobsOri=nobs; - if(noConstr) - { - nConstr=0; - nConstrLong=0; - nConstrLat=0; - nConstrMuLong=0; - nConstrMuLat=0; - } else - { - for(int q=0;q<nConstrLat;q++) - if(constrLatId[q]>=nStar) - { - printf("PE=%d Error invalit Lat Constraint %ld\n",myid,constrLatId[q]); - MPI_Abort(MPI_COMM_WORLD,1); + + nObsxStar = nobs / nStar; + nobsOri = nobs; + if (noConstr) + { + nConstr = 0; + nConstrLong = 0; + nConstrLat = 0; + nConstrMuLong = 0; + nConstrMuLat = 0; + } + else + { + for (int q = 0; q < nConstrLat; q++) + if (constrLatId[q] >= nStar) + { + printf("PE=%d Error invalit Lat Constraint %ld\n", myid, constrLatId[q]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - - for(int q=0;q<nConstrLong;q++) - if(constrLongId[q]>=nStar) + + for (int q = 0; q < nConstrLong; q++) + if (constrLongId[q] >= nStar) { - printf("PE=%d Error invalit Long Constraint %ld\n",myid,constrLongId[q]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error invalit Long Constraint %ld\n", myid, constrLongId[q]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - for(int q=0;q<nConstrMuLat;q++) - if(constrMuLatId[q]>=nStar) + for (int q = 0; q < nConstrMuLat; q++) + if (constrMuLatId[q] >= nStar) { - printf("PE=%d Error invalit MuLat Constraint %ld\n",myid,constrMuLatId[q]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error invalit MuLat Constraint %ld\n", myid, constrMuLatId[q]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - - for(int q=0;q<nConstrMuLong;q++) - if(constrMuLongId[q]>=nStar) + + for (int q = 0; q < nConstrMuLong; q++) + if (constrMuLongId[q] >= nStar) { - printf("PE=%d Error invalit MuLat Constraint %ld\n",myid,constrMuLongId[q]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error invalit MuLat Constraint %ld\n", myid, constrMuLongId[q]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - + nConstr = nConstrLong + nConstrLat + nConstrMuLong + nConstrMuLat; // number of constraints to be generated } - - - nobs+=nConstr; - nunk = ((long) nAstroParam) + nAttParam + nInstrParam + nGlobalParam; // number of unknowns (i.e. columns of the system matrix) - nparam = nAstroPSolved + nAttP + nInstrPSolved + nGlobP; // number of non-zero coefficients for each observation (i.e. for each system row) - if(nparam==0){ - printf("Abort. Empty system nparam=0 . nAstroPSolved=%d nAttP=%d nInstrPSolved=%d nGlobP=%d\n",nAstroPSolved,nAttP,nInstrPSolved,nGlobP); - MPI_Abort(MPI_COMM_WORLD,1); + + nobs += nConstr; + nunk = ((long)nAstroParam) + nAttParam + nInstrParam + nGlobalParam; // number of unknowns (i.e. columns of the system matrix) + nparam = nAstroPSolved + nAttP + nInstrPSolved + nGlobP; // number of non-zero coefficients for each observation (i.e. for each system row) + if (nparam == 0) + { + printf("Abort. Empty system nparam=0 . nAstroPSolved=%d nAttP=%d nInstrPSolved=%d nGlobP=%d\n", nAstroPSolved, nAttP, nInstrPSolved, nGlobP); + MPI_Abort(MPI_COMM_WORLD, 1); } ncoeff = nparam * nobs; // total number of non-zero coefficients of the system - - if(nobs <=nunk){ - printf("SEVERE ERROR: number of equations=%ld and number of unknown=%ld make solution unsafe\n",nobs,nunk); - MPI_Abort(MPI_COMM_WORLD,1); - exit(EXIT_FAILURE); + if (nobs <= nunk) + { + printf("SEVERE ERROR: number of equations=%ld and number of unknown=%ld make solution unsafe\n", nobs, nunk); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(EXIT_FAILURE); } - + // Start map distributed array - mapNoss=(long int *) calloc(nproc,sizeof(long int)); - mapNcoeff=(long int *) calloc(nproc,sizeof(long int)); - mapNossAfter=0; - mapNcoeffAfter=0; - mapNossBefore=0; - mapNcoeffBefore=0; - for(i=0;i<nproc;i++) + mapNoss = (long int *)calloc(nproc, sizeof(long int)); + mapNcoeff = (long int *)calloc(nproc, sizeof(long int)); + mapNossAfter = 0; + mapNcoeffAfter = 0; + mapNossBefore = 0; + mapNcoeffBefore = 0; + for (i = 0; i < nproc; i++) { - mapNoss[i]=(nobs)/nproc; - if(nobs % nproc >=i+1) mapNoss[i]++; - mapNcoeff[i]=mapNoss[i]*nparam; - if(i<myid) + mapNoss[i] = (nobs) / nproc; + if (nobs % nproc >= i + 1) + mapNoss[i]++; + mapNcoeff[i] = mapNoss[i] * nparam; + if (i < myid) { - mapNossBefore+=mapNoss[i]; - mapNcoeffBefore+=mapNcoeff[i]; + mapNossBefore += mapNoss[i]; + mapNcoeffBefore += mapNcoeff[i]; } - if(i>myid) + if (i > myid) { - mapNossAfter+=mapNoss[i]; - mapNcoeffAfter+=mapNcoeff[i]; + mapNossAfter += mapNoss[i]; + mapNcoeffAfter += mapNcoeff[i]; } } ////////////////// Simulating the ... of NObsxStar file - if(extConstraint){ - int * sumNObsxStar; - sumNObsxStar=(int *) calloc(nStar, sizeof(int)); - int irest=nobs % nStar; - for(int i=0;i<nStar;i++){ - sumNObsxStar[i]=nobs/nStar; - if(i<irest) sumNObsxStar[i]++; - } - if(wrFilebin && myid==0){ + if (extConstraint) + { + int *sumNObsxStar; + sumNObsxStar = (int *)calloc(nStar, sizeof(int)); + int irest = nobs % nStar; + for (int i = 0; i < nStar; i++) + { + sumNObsxStar[i] = nobs / nStar; + if (i < irest) + sumNObsxStar[i]++; + } + if (wrFilebin && myid == 0) + { chdir(wpath); chdir(wrfileDir); FILE *fpNObsxStar; - fpNObsxStar=fopen("NObsStar.bin","wb"); - fwrite(sumNObsxStar,sizeof(int),nStar,fpNObsxStar); + fpNObsxStar = fopen("NObsStar.bin", "wb"); + fwrite(sumNObsxStar, sizeof(int), nStar, fpNObsxStar); fclose(fpNObsxStar); chdir(wpath); - - } - long counterObsxStar=0; - for(int i=0;i<nStar;i++){ - counterObsxStar+=sumNObsxStar[i]; - if(counterObsxStar>mapNossBefore && firstStarConstr==-1) firstStarConstr=i; //first star assigned in extConstr - if(counterObsxStar>=mapNossBefore+mapNoss[myid] && lastStarConstr==-1){ - lastStarConstr=i; //last star assigned in extConstr (it will be eqaul to lastrStar-1 in case of overlap) - if(counterObsxStar>(mapNossBefore+mapNoss[myid]) && myid!=(nproc-1)){ - starOverlap=1; + } + long counterObsxStar = 0; + for (int i = 0; i < nStar; i++) + { + counterObsxStar += sumNObsxStar[i]; + if (counterObsxStar > mapNossBefore && firstStarConstr == -1) + firstStarConstr = i; //first star assigned in extConstr + if (counterObsxStar >= mapNossBefore + mapNoss[myid] && lastStarConstr == -1) + { + lastStarConstr = i; //last star assigned in extConstr (it will be eqaul to lastrStar-1 in case of overlap) + if (counterObsxStar > (mapNossBefore + mapNoss[myid]) && myid != (nproc - 1)) + { + starOverlap = 1; lastStarConstr--; } break; } } - numOfExtStar=lastStarConstr-firstStarConstr+1; //number of stars computed in ext Constr - - int counterAttCols=0; - startingAttColExtConstr=0; // numero di colonna di assetto escluso l'offset: la prima è 0 per il PE0 x asse - endingAttColExtConstr=0; // numero di colonna di assetto finale l'offset: la prima è nDegFreedomAtt/nproc-1 (+1 in caso di modulo) per il PE0 x asse - int attRes=nDegFreedomAtt%nproc; - startingAttColExtConstr=(nDegFreedomAtt/nproc)*myid; - if(myid<attRes)startingAttColExtConstr+=myid; - else startingAttColExtConstr+=attRes; - endingAttColExtConstr=startingAttColExtConstr+(nDegFreedomAtt/nproc)-1; - if(myid<attRes)endingAttColExtConstr++; - - - numOfExtAttCol=endingAttColExtConstr-startingAttColExtConstr+1; //numeroi di colonne x asse + numOfExtStar = lastStarConstr - firstStarConstr + 1; //number of stars computed in ext Constr + + int counterAttCols = 0; + startingAttColExtConstr = 0; // numero di colonna di assetto escluso l'offset: la prima è 0 per il PE0 x asse + endingAttColExtConstr = 0; // numero di colonna di assetto finale l'offset: la prima è nDegFreedomAtt/nproc-1 (+1 in caso di modulo) per il PE0 x asse + int attRes = nDegFreedomAtt % nproc; + startingAttColExtConstr = (nDegFreedomAtt / nproc) * myid; + if (myid < attRes) + startingAttColExtConstr += myid; + else + startingAttColExtConstr += attRes; + endingAttColExtConstr = startingAttColExtConstr + (nDegFreedomAtt / nproc) - 1; + if (myid < attRes) + endingAttColExtConstr++; + + numOfExtAttCol = endingAttColExtConstr - startingAttColExtConstr + 1; //numeroi di colonne x asse } //////////////////// barConstraint - if(barConstraint){ - int * sumNObsxStar; - sumNObsxStar=(int *) calloc(nStar, sizeof(int)); - int irest=nobs % nStar; - for(int i=0;i<nStar;i++){ - sumNObsxStar[i]=nobs/nStar; - if(i<irest) sumNObsxStar[i]++; - } - if(wrFilebin && myid==0){ + if (barConstraint) + { + int *sumNObsxStar; + sumNObsxStar = (int *)calloc(nStar, sizeof(int)); + int irest = nobs % nStar; + for (int i = 0; i < nStar; i++) + { + sumNObsxStar[i] = nobs / nStar; + if (i < irest) + sumNObsxStar[i]++; + } + if (wrFilebin && myid == 0) + { chdir(wpath); chdir(wrfileDir); FILE *fpNObsxStar; - fpNObsxStar=fopen("NObsStar.bin","wb"); - fwrite(sumNObsxStar,sizeof(int),nStar,fpNObsxStar); + fpNObsxStar = fopen("NObsStar.bin", "wb"); + fwrite(sumNObsxStar, sizeof(int), nStar, fpNObsxStar); fclose(fpNObsxStar); chdir(wpath); - - } - int counterObsxStar=0; - for(int i=0;i<nStar;i++){ - counterObsxStar+=sumNObsxStar[i]; - if(counterObsxStar>mapNossBefore && firstStarConstr==-1) firstStarConstr=i; //first star assigned in barConstr - if(counterObsxStar>=mapNossBefore+mapNoss[myid] && lastStarConstr==-1){ - lastStarConstr=i; //last star assigned in barConstr (it will be eqaul to lastrStar-1 in case of overlap) - if(counterObsxStar>(mapNossBefore+mapNoss[myid]) && myid!=(nproc-1)){ - starOverlap=1; + } + int counterObsxStar = 0; + for (int i = 0; i < nStar; i++) + { + counterObsxStar += sumNObsxStar[i]; + if (counterObsxStar > mapNossBefore && firstStarConstr == -1) + firstStarConstr = i; //first star assigned in barConstr + if (counterObsxStar >= mapNossBefore + mapNoss[myid] && lastStarConstr == -1) + { + lastStarConstr = i; //last star assigned in barConstr (it will be eqaul to lastrStar-1 in case of overlap) + if (counterObsxStar > (mapNossBefore + mapNoss[myid]) && myid != (nproc - 1)) + { + starOverlap = 1; lastStarConstr--; } break; } } - numOfBarStar=lastStarConstr-firstStarConstr+1; //number of stars computed in bar Constr - + numOfBarStar = lastStarConstr - firstStarConstr + 1; //number of stars computed in bar Constr } ////////////////////// comlsqr - - - - comlsqr.nStar=nStar; - comlsqr.nAstroP=nAstroP; - comlsqr.nAstroPSolved=nAstroPSolved; - comlsqr.nAttP=nAttP; - comlsqr.nInstrP=nInstrP; - comlsqr.nInstrPSolved=nInstrPSolved; - comlsqr.nGlobP=nGlobP; - comlsqr.mapNossBefore=mapNossBefore; - comlsqr.mapNossAfter=mapNossAfter; - comlsqr.myid=myid; - comlsqr.nproc=nproc; - comlsqr.mapNoss=mapNoss; - comlsqr.mapNcoeff=mapNcoeff; - comlsqr.multMI=multMI; - comlsqr.debugMode=debugMode; - comlsqr.noCPR=noCPR; - comlsqr.nAttParam=nAttParam; - comlsqr.extConstraint=extConstraint; - comlsqr.nEqExtConstr=nEqExtConstr; - comlsqr.numOfExtStar=numOfExtStar; - comlsqr.barConstraint=barConstraint; - comlsqr.nEqBarConstr=nEqBarConstr; - comlsqr.numOfBarStar=numOfBarStar; - comlsqr.firstStarConstr=firstStarConstr; - comlsqr.lastStarConstr=lastStarConstr; - comlsqr.numOfExtAttCol=numOfExtAttCol; - comlsqr.startingAttColExtConstr=startingAttColExtConstr; - comlsqr.setBound[0]=0; - comlsqr.setBound[1]=nAstroPSolved; - comlsqr.setBound[2]=nAstroPSolved+nAttP; - comlsqr.setBound[3]=nAstroPSolved+nAttP+nInstrPSolved; - comlsqr.nDegFreedomAtt=nDegFreedomAtt; - comlsqr.nAttParAxis=nAttParAxis; - comlsqr.nAttAxes=nAttAxes; - comlsqr.nobs=nobs; - comlsqr.lsInstrFlag=lsInstrFlag; - comlsqr.ssInstrFlag=ssInstrFlag; - comlsqr.nuInstrFlag=nuInstrFlag; - comlsqr.maInstrFlag=maInstrFlag; - comlsqr.myid=myid; - comlsqr.cCDLSAACZP=cCDLSAACZP; - comlsqr.nOfInstrConstr=nOfInstrConstr; - comlsqr.nElemIC=nElemIC; - comlsqr.nElemICLSAL=nElemICLSAL; - comlsqr.nElemICLSAC=nElemICLSAC; - comlsqr.nElemICSS=nElemICSS; - comlsqr.instrConst[0]=instrConst[0]; - comlsqr.instrConst[1]=instrConst[1]; - comlsqr.instrConst[2]=instrConst[2]; - comlsqr.instrConst[3]=instrConst[3]; - comlsqr.nInstrParam=nInstrParam; - comlsqr.nGlobalParam=nGlobalParam; + + comlsqr.nStar = nStar; + comlsqr.nAstroP = nAstroP; + comlsqr.nAstroPSolved = nAstroPSolved; + comlsqr.nAttP = nAttP; + comlsqr.nInstrP = nInstrP; + comlsqr.nInstrPSolved = nInstrPSolved; + comlsqr.nGlobP = nGlobP; + comlsqr.mapNossBefore = mapNossBefore; + comlsqr.mapNossAfter = mapNossAfter; + comlsqr.myid = myid; + comlsqr.nproc = nproc; + comlsqr.mapNoss = mapNoss; + comlsqr.mapNcoeff = mapNcoeff; + comlsqr.multMI = multMI; + comlsqr.debugMode = debugMode; + comlsqr.noCPR = noCPR; + comlsqr.nAttParam = nAttParam; + comlsqr.extConstraint = extConstraint; + comlsqr.nEqExtConstr = nEqExtConstr; + comlsqr.numOfExtStar = numOfExtStar; + comlsqr.barConstraint = barConstraint; + comlsqr.nEqBarConstr = nEqBarConstr; + comlsqr.numOfBarStar = numOfBarStar; + comlsqr.firstStarConstr = firstStarConstr; + comlsqr.lastStarConstr = lastStarConstr; + comlsqr.numOfExtAttCol = numOfExtAttCol; + comlsqr.startingAttColExtConstr = startingAttColExtConstr; + comlsqr.setBound[0] = 0; + comlsqr.setBound[1] = nAstroPSolved; + comlsqr.setBound[2] = nAstroPSolved + nAttP; + comlsqr.setBound[3] = nAstroPSolved + nAttP + nInstrPSolved; + comlsqr.nDegFreedomAtt = nDegFreedomAtt; + comlsqr.nAttParAxis = nAttParAxis; + comlsqr.nAttAxes = nAttAxes; + comlsqr.nobs = nobs; + comlsqr.lsInstrFlag = lsInstrFlag; + comlsqr.ssInstrFlag = ssInstrFlag; + comlsqr.nuInstrFlag = nuInstrFlag; + comlsqr.maInstrFlag = maInstrFlag; + comlsqr.myid = myid; + comlsqr.cCDLSAACZP = cCDLSAACZP; + comlsqr.nOfInstrConstr = nOfInstrConstr; + comlsqr.nElemIC = nElemIC; + comlsqr.nElemICLSAL = nElemICLSAL; + comlsqr.nElemICLSAC = nElemICLSAC; + comlsqr.nElemICSS = nElemICSS; + comlsqr.instrConst[0] = instrConst[0]; + comlsqr.instrConst[1] = instrConst[1]; + comlsqr.instrConst[2] = instrConst[2]; + comlsqr.instrConst[3] = instrConst[3]; + comlsqr.nInstrParam = nInstrParam; + comlsqr.nGlobalParam = nGlobalParam; + + comlsqr.nthreads= nthreads; + comlsqr.ntasks= ntasks; + ///////////////////// end buidl map distributed arrays - + // Allocate the memory for the vectors and compute the total memory allocated totmem = 0; nElements = mapNcoeff[myid]; - if (extConstraint){ - addElementextStar= (lastStarConstr-firstStarConstr+1)*nAstroPSolved; - addElementAtt=numOfExtAttCol*nAttAxes; + if (extConstraint) + { + addElementextStar = (lastStarConstr - firstStarConstr + 1) * nAstroPSolved; + addElementAtt = numOfExtAttCol * nAttAxes; } - if (barConstraint){ - addElementbarStar= (lastStarConstr-firstStarConstr+1)*nAstroPSolved; + if (barConstraint) + { + addElementbarStar = (lastStarConstr - firstStarConstr + 1) * nAstroPSolved; } - nOfElextObs=addElementextStar+addElementAtt; - nOfElBarObs=addElementbarStar; - comlsqr.nOfElextObs=nOfElextObs; - comlsqr.nOfElBarObs=nOfElBarObs; + nOfElextObs = addElementextStar + addElementAtt; + nOfElBarObs = addElementbarStar; + comlsqr.nOfElextObs = nOfElextObs; + comlsqr.nOfElBarObs = nOfElBarObs; - nElements+=nOfElextObs*nEqExtConstr+nOfElBarObs*nEqBarConstr+nElemIC; - - systemMatrix = (double *) calloc(nElements,sizeof(double)); + nElements += nOfElextObs * nEqExtConstr + nOfElBarObs * nEqBarConstr + nElemIC; + + systemMatrix = (double *)calloc(nElements, sizeof(double)); if (!systemMatrix) - exit(err_malloc("systemMatrix",myid)); - totmem += nElements*sizeof(double); - - nElements = mapNoss[myid]*multMI; - matrixIndex = (long int *) calloc(nElements, sizeof(long int)); + exit(err_malloc("systemMatrix", myid)); + totmem += nElements * sizeof(double); + + nElements = mapNoss[myid] * multMI; + matrixIndex = (long int *)calloc(nElements, sizeof(long int)); if (!matrixIndex) - exit(err_malloc("matrixIndex",myid)); - totmem += nElements* sizeof(long int); - - nElements = mapNoss[myid]*nInstrPSolved+nElemIC; - instrCol = (int *) calloc(nElements, sizeof(int)); + exit(err_malloc("matrixIndex", myid)); + totmem += nElements * sizeof(long int); + + nElements = mapNoss[myid] * nInstrPSolved + nElemIC; + instrCol = (int *)calloc(nElements, sizeof(int)); if (!instrCol) - exit(err_malloc("instrCol",myid)); - totmem += nElements* sizeof(int); + exit(err_malloc("instrCol", myid)); + totmem += nElements * sizeof(int); nElements = nOfInstrConstr; - instrConstrIlung = (int *) calloc(nElements, sizeof(int)); // it is the vectorr that for each observation (in this PE) save the INDEX for the values of instr + instrConstrIlung = (int *)calloc(nElements, sizeof(int)); // it is the vectorr that for each observation (in this PE) save the INDEX for the values of instr if (!instrConstrIlung) - exit(err_malloc("instrConstrIlung",myid)); - totmem += nElements* sizeof(int); - - + exit(err_malloc("instrConstrIlung", myid)); + totmem += nElements * sizeof(int); + nElements = mapNoss[myid]; - if(extConstraint) nElements+=nEqExtConstr; - if(barConstraint) nElements+=nEqBarConstr; - if(nOfInstrConstr>0) nElements+=nOfInstrConstr; - knownTerms = (double *) calloc(nElements, sizeof(double)); + if (extConstraint) + nElements += nEqExtConstr; + if (barConstraint) + nElements += nEqBarConstr; + if (nOfInstrConstr > 0) + nElements += nOfInstrConstr; + knownTerms = (double *)calloc(nElements, sizeof(double)); if (!knownTerms) - exit(err_malloc("knownTerms",myid)); - totmem += nElements* sizeof(double); - + exit(err_malloc("knownTerms", myid)); + totmem += nElements * sizeof(double); + ielem = 0; offsetAttParam = nAstroParam; offsetInstrParam = offsetAttParam + nAttParam; offsetGlobParam = offsetInstrParam + nInstrParam; - comlsqr.offsetAttParam=offsetAttParam; - - - long rowsxFile=nobsOri/(nproc*nfileProc); - - if(withFile) - { - char filenameSim_SM[128]="SIM_PE_SM_"; - char filenameSim_MI[128]="SIM_PE_MI_"; - char filenameSim_II[128]="SIM_PE_II_"; - char filenameSim_KT[128]="SIM_PE_KT_"; - char varpe[32]=""; - char varrows[32]=""; - sprintf(varpe,"%d",myid); - sprintf(varrows,"%ld",rowsxFile); - strcat(filenameSim_SM,varrows); - strcat(filenameSim_SM,"_"); - strcat(filenameSim_SM,varpe); - strcat(filenameSim_SM,".bin"); - strcat(filenameSim_MI,varrows); - strcat(filenameSim_MI,"_"); - strcat(filenameSim_MI,varpe); - strcat(filenameSim_MI,".bin"); - strcat(filenameSim_II,varrows); - strcat(filenameSim_II,"_"); - strcat(filenameSim_II,varpe); - strcat(filenameSim_II,".bin"); - strcat(filenameSim_KT,varrows); - strcat(filenameSim_KT,"_"); - strcat(filenameSim_KT,varpe); - strcat(filenameSim_KT,".bin"); - + comlsqr.offsetAttParam = offsetAttParam; + + long rowsxFile = nobsOri / (nproc * nfileProc); + + if (withFile) + { + char filenameSim_SM[128] = "SIM_PE_SM_"; + char filenameSim_MI[128] = "SIM_PE_MI_"; + char filenameSim_II[128] = "SIM_PE_II_"; + char filenameSim_KT[128] = "SIM_PE_KT_"; + char varpe[32] = ""; + char varrows[32] = ""; + sprintf(varpe, "%d", myid); + sprintf(varrows, "%ld", rowsxFile); + strcat(filenameSim_SM, varrows); + strcat(filenameSim_SM, "_"); + strcat(filenameSim_SM, varpe); + strcat(filenameSim_SM, ".bin"); + strcat(filenameSim_MI, varrows); + strcat(filenameSim_MI, "_"); + strcat(filenameSim_MI, varpe); + strcat(filenameSim_MI, ".bin"); + strcat(filenameSim_II, varrows); + strcat(filenameSim_II, "_"); + strcat(filenameSim_II, varpe); + strcat(filenameSim_II, ".bin"); + strcat(filenameSim_KT, varrows); + strcat(filenameSim_KT, "_"); + strcat(filenameSim_KT, varpe); + strcat(filenameSim_KT, ".bin"); + double *smsim; - smsim=(double *)calloc(rowsxFile*nparam,sizeof(double)); - fpSM=fopen(filenameSim_SM,"wb"); - fwrite(smsim,sizeof(double),rowsxFile*nparam,fpSM); + smsim = (double *)calloc(rowsxFile * nparam, sizeof(double)); + fpSM = fopen(filenameSim_SM, "wb"); + fwrite(smsim, sizeof(double), rowsxFile * nparam, fpSM); fclose(fpSM); - fpKT=fopen(filenameSim_KT,"wb"); - fwrite(smsim,sizeof(double),rowsxFile,fpKT); + fpKT = fopen(filenameSim_KT, "wb"); + fwrite(smsim, sizeof(double), rowsxFile, fpKT); fclose(fpKT); free(smsim); int *intsim; - intsim=(int *)calloc(rowsxFile*nInstrPSolved,sizeof(int)); - fpII=fopen(filenameSim_II,"wb"); - fwrite(intsim,sizeof(int),rowsxFile*nInstrPSolved,fpII); + intsim = (int *)calloc(rowsxFile * nInstrPSolved, sizeof(int)); + fpII = fopen(filenameSim_II, "wb"); + fwrite(intsim, sizeof(int), rowsxFile * nInstrPSolved, fpII); fclose(fpII); free(intsim); long *misim; - misim=(long *)calloc(rowsxFile*multMI,sizeof(long)); - fpMI=fopen(filenameSim_MI,"wb"); - fwrite(misim,sizeof(long),rowsxFile*multMI,fpMI); + misim = (long *)calloc(rowsxFile * multMI, sizeof(long)); + fpMI = fopen(filenameSim_MI, "wb"); + fwrite(misim, sizeof(long), rowsxFile * multMI, fpMI); fclose(fpMI); free(misim); long nrowToRead; - if(myid==0) printf( - "Found %d SM data files in the directory. Reading the coefficients...\n", - (nfileProc)*nproc); - timeToReadFiles=MPI_Wtime(); - - for(ii=0;ii<nfileProc+2;ii++) { - - if(ii==0 && myid==0) printf("PE=%d Opening %d and reading %s and associated files\n",myid,nfileProc,filenameSim_SM); - - fpSM=fopen(filenameSim_SM,"rb"); + if (myid == 0) + printf( + "Found %d SM data files in the directory. Reading the coefficients...\n", + (nfileProc)*nproc); + timeToReadFiles = MPI_Wtime(); + + for (ii = 0; ii < nfileProc + 2; ii++) + { + + if (ii == 0 && myid == 0) + printf("PE=%d Opening %d and reading %s and associated files\n", myid, nfileProc, filenameSim_SM); + + fpSM = fopen(filenameSim_SM, "rb"); if (!fpSM) { - printf("PE=%d Error while open %s\n",myid,filenameSim_SM); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error while open %s\n", myid, filenameSim_SM); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - fpMI=fopen(filenameSim_MI,"rb"); + fpMI = fopen(filenameSim_MI, "rb"); if (!fpMI) { - printf("PE=%d Error while open %s\n",myid,filenameSim_MI); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error while open %s\n", myid, filenameSim_MI); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - fpII=fopen(filenameSim_II,"rb"); + fpII = fopen(filenameSim_II, "rb"); if (!fpII) { - printf("PE=%d Error while open %s\n",myid,filenameSim_II); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error while open %s\n", myid, filenameSim_II); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - fpKT=fopen(filenameSim_KT,"rb"); + fpKT = fopen(filenameSim_KT, "rb"); if (!fpSM) { - printf("PE=%d Error while open %s\n",myid,filenameSim_KT); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error while open %s\n", myid, filenameSim_KT); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - - + ///// Reading systemMatrix - if(ii==0 || ii==nfileProc+1) - { - if(ii==0) fseek(fpSM,((rowsxFile*nparam)/2)*sizeof(double),SEEK_SET); - fread(systemMatrix,sizeof(double),((rowsxFile*nparam)/2)*sizeof(double),fpSM); - if(ii==0) fseek(fpMI,((rowsxFile*multMI)/2)*sizeof(long),SEEK_SET); - fread(matrixIndex,sizeof(long),((rowsxFile*multMI)/2)*sizeof(double),fpMI); - if(ii==0) fseek(fpII,((rowsxFile*nInstrPSolved)/2)*sizeof(long),SEEK_SET); - fread(instrCol,sizeof(int),((rowsxFile*nInstrPSolved)/2)*sizeof(int),fpII); - if(ii==0) fseek(fpKT,((rowsxFile)/2)*sizeof(double),SEEK_SET); - fread(instrCol,sizeof(int),((rowsxFile)/2)*sizeof(double),fpKT); - } else{ - fread(systemMatrix,sizeof(double),((rowsxFile*nparam))*sizeof(double),fpSM); - fread(matrixIndex,sizeof(long),((rowsxFile*multMI))*sizeof(double),fpMI); - fread(instrCol,sizeof(int),((rowsxFile*nInstrPSolved))*sizeof(int),fpII); - fread(systemMatrix,sizeof(double),((rowsxFile))*sizeof(double),fpKT); + if (ii == 0 || ii == nfileProc + 1) + { + if (ii == 0) + fseek(fpSM, ((rowsxFile * nparam) / 2) * sizeof(double), SEEK_SET); + fread(systemMatrix, sizeof(double), ((rowsxFile * nparam) / 2) * sizeof(double), fpSM); + if (ii == 0) + fseek(fpMI, ((rowsxFile * multMI) / 2) * sizeof(long), SEEK_SET); + fread(matrixIndex, sizeof(long), ((rowsxFile * multMI) / 2) * sizeof(double), fpMI); + if (ii == 0) + fseek(fpII, ((rowsxFile * nInstrPSolved) / 2) * sizeof(long), SEEK_SET); + fread(instrCol, sizeof(int), ((rowsxFile * nInstrPSolved) / 2) * sizeof(int), fpII); + if (ii == 0) + fseek(fpKT, ((rowsxFile) / 2) * sizeof(double), SEEK_SET); + fread(instrCol, sizeof(int), ((rowsxFile) / 2) * sizeof(double), fpKT); + } + else + { + fread(systemMatrix, sizeof(double), ((rowsxFile * nparam)) * sizeof(double), fpSM); + fread(matrixIndex, sizeof(long), ((rowsxFile * multMI)) * sizeof(double), fpMI); + fread(instrCol, sizeof(int), ((rowsxFile * nInstrPSolved)) * sizeof(int), fpII); + fread(systemMatrix, sizeof(double), ((rowsxFile)) * sizeof(double), fpKT); } fclose(fpSM); fclose(fpMI); fclose(fpII); fclose(fpKT); - + } //for(ii) MPI_Barrier(MPI_COMM_WORLD); - timeToReadFiles=MPI_Wtime()-timeToReadFiles; - if(myid==0) printf("PE=%d time seconds=%lf TO READ %d Files\n",myid, timeToReadFiles,nfileProc); - }// if withFile (no external and baricentric Contraint are simulated for reading time - timeToReadFiles=MPI_Wtime(); - - long startingStar=0; - long obsTotal=0; - int residual=0; //represents the number of observation for the staring stars (if equal to zero the number of observations for the starting star is nObsxStar) + timeToReadFiles = MPI_Wtime() - timeToReadFiles; + if (myid == 0) + printf("PE=%d time seconds=%lf TO READ %d Files\n", myid, timeToReadFiles, nfileProc); + } // if withFile (no external and baricentric Contraint are simulated for reading time + timeToReadFiles = MPI_Wtime(); + + long startingStar = 0; + long obsTotal = 0; + int residual = 0; //represents the number of observation for the staring stars (if equal to zero the number of observations for the starting star is nObsxStar) ///////// - for(int p=0;p<myid;p++) + for (int p = 0; p < myid; p++) { - while(obsTotal<mapNoss[p]) + while (obsTotal < mapNoss[p]) { - if(residual==0) + if (residual == 0) { - obsTotal+=nObsxStar; - if(startingStar<nobsOri%nStar) obsTotal++; - if(nConstr>0) + obsTotal += nObsxStar; + if (startingStar < nobsOri % nStar) + obsTotal++; + if (nConstr > 0) { - for(int q=0;q<nConstrLat;q++) - if(constrLatId[q]==startingStar) obsTotal++; - for(int q=0;q<nConstrLong;q++) - if(constrLongId[q]==startingStar) obsTotal++; - for(int q=0;q<nConstrMuLat;q++) - if(constrMuLatId[q]==startingStar) obsTotal++; - for(int q=0;q<nConstrMuLong;q++) - if(constrMuLongId[q]==startingStar) obsTotal++; + for (int q = 0; q < nConstrLat; q++) + if (constrLatId[q] == startingStar) + obsTotal++; + for (int q = 0; q < nConstrLong; q++) + if (constrLongId[q] == startingStar) + obsTotal++; + for (int q = 0; q < nConstrMuLat; q++) + if (constrMuLatId[q] == startingStar) + obsTotal++; + for (int q = 0; q < nConstrMuLong; q++) + if (constrMuLongId[q] == startingStar) + obsTotal++; } - } else { //if residual - obsTotal=residual; - residual=0; - } - - if(obsTotal<=mapNoss[p])startingStar++; - }//while - residual=obsTotal-mapNoss[p]; - obsTotal=0; + } + else + { //if residual + obsTotal = residual; + residual = 0; + } + + if (obsTotal <= mapNoss[p]) + startingStar++; + } //while + residual = obsTotal - mapNoss[p]; + obsTotal = 0; } // for in p ////////////////////////// - if(debugMode) printf("PE=%d mapNoss[myid]=%ld starting star %ld residual=%d\n",myid,mapNoss[myid],startingStar,residual); - + if (debugMode) + printf("PE=%d mapNoss[myid]=%ld starting star %ld residual=%d\n", myid, mapNoss[myid], startingStar, residual); + //////////////// filling the system - long currentStar=startingStar; - int obsStar=residual; + long currentStar = startingStar; + int obsStar = residual; int obsStarnow; - int numOfObslast=0; - long startFreedom=(nDegFreedomAtt/nproc)*myid; - long endFreedom=startFreedom+(nDegFreedomAtt/nproc)+1; - long lastFreedom=startFreedom; - int freedomReached=0; - long instrStartFreedom=(nInstrParam/nproc)*myid; - long instrEndFreedom=instrStartFreedom+(nInstrParam/nproc)+1; - if(myid==nproc-1) - instrEndFreedom=nInstrParam-1; - int instrFreedomReached=0; - int isConstraint=0; - int instrLastFreedom=instrStartFreedom; + int numOfObslast = 0; + long startFreedom = (nDegFreedomAtt / nproc) * myid; + long endFreedom = startFreedom + (nDegFreedomAtt / nproc) + 1; + long lastFreedom = startFreedom; + int freedomReached = 0; + long instrStartFreedom = (nInstrParam / nproc) * myid; + long instrEndFreedom = instrStartFreedom + (nInstrParam / nproc) + 1; + if (myid == nproc - 1) + instrEndFreedom = nInstrParam - 1; + int instrFreedomReached = 0; + int isConstraint = 0; + int instrLastFreedom = instrStartFreedom; srand(myid); - if(debugMode) - printf("PE=%d instrStartFreedom=%ld instrEndFreedom=%ld nInstrParam=%d\n",myid,instrStartFreedom,instrEndFreedom,nInstrParam); - if(obsStar==0) - { - obsStar=nObsxStar; - if(currentStar<nobsOri%nStar) obsStar++; - if(nConstr>0) - { - for(int q=0;q<nConstrLat;q++) - if(constrLatId[q]==currentStar) obsStar++; - for(int q=0;q<nConstrLong;q++) - if(constrLongId[q]==currentStar) obsStar++; - for(int q=0;q<nConstrMuLat;q++) - if(constrMuLatId[q]==currentStar) obsStar++; - for(int q=0;q<nConstrLong;q++) - if(constrMuLongId[q]==currentStar) obsStar++; - } - - } - obsStarnow=obsStar; - if(nConstr>0) - { - for(int q=0;q<nConstrLat;q++) - if(constrLatId[q]==currentStar) isConstraint++; - for(int q=0;q<nConstrLong;q++) - if(constrLongId[q]==currentStar) isConstraint++; - for(int q=0;q<nConstrMuLat;q++) - if(constrMuLatId[q]==currentStar) isConstraint++; - for(int q=0;q<nConstrMuLong;q++) - if(constrMuLongId[q]==currentStar) isConstraint++; - } - - int offsetConstraint=isConstraint-obsStar; // number of constraint alredy computed in the previous PE - if(offsetConstraint<0)offsetConstraint=0; - - - int counterStarObs=0; - rowInFile=-1; - int changedStar=0; - int counterConstr=0; + if (debugMode) + printf("PE=%d instrStartFreedom=%ld instrEndFreedom=%ld nInstrParam=%d\n", myid, instrStartFreedom, instrEndFreedom, nInstrParam); + if (obsStar == 0) + { + obsStar = nObsxStar; + if (currentStar < nobsOri % nStar) + obsStar++; + if (nConstr > 0) + { + for (int q = 0; q < nConstrLat; q++) + if (constrLatId[q] == currentStar) + obsStar++; + for (int q = 0; q < nConstrLong; q++) + if (constrLongId[q] == currentStar) + obsStar++; + for (int q = 0; q < nConstrMuLat; q++) + if (constrMuLatId[q] == currentStar) + obsStar++; + for (int q = 0; q < nConstrLong; q++) + if (constrMuLongId[q] == currentStar) + obsStar++; + } + } + obsStarnow = obsStar; + if (nConstr > 0) + { + for (int q = 0; q < nConstrLat; q++) + if (constrLatId[q] == currentStar) + isConstraint++; + for (int q = 0; q < nConstrLong; q++) + if (constrLongId[q] == currentStar) + isConstraint++; + for (int q = 0; q < nConstrMuLat; q++) + if (constrMuLatId[q] == currentStar) + isConstraint++; + for (int q = 0; q < nConstrMuLong; q++) + if (constrMuLongId[q] == currentStar) + isConstraint++; + } + + int offsetConstraint = isConstraint - obsStar; // number of constraint alredy computed in the previous PE + if (offsetConstraint < 0) + offsetConstraint = 0; + + int counterStarObs = 0; + rowInFile = -1; + int changedStar = 0; + int counterConstr = 0; ///////////////////////////////// /////////// RUNNING ON ALL OBSERVATIONS ///////////////////////////////// - for(ii=0;ii<mapNoss[myid];ii++) + for (ii = 0; ii < mapNoss[myid]; ii++) { rowInFile++; - if(currentStar%1000==0 && changedStar){ - rowInFile=0; - changedStar=0; + if (currentStar % 1000 == 0 && changedStar) + { + rowInFile = 0; + changedStar = 0; } ///////////// generate MatrixIndex - if(currentStar==nStar) + if (currentStar == nStar) { - printf("PE=%d Severe Error in currentStar=%ld ii=%ld\n",myid,currentStar,ii); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Severe Error in currentStar=%ld ii=%ld\n", myid, currentStar, ii); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - if(nAstroPSolved) matrixIndex[ii*multMI]=currentStar*nAstroPSolved; - - if(!freedomReached && nAstroPSolved) + if (nAstroPSolved) + matrixIndex[ii * multMI] = currentStar * nAstroPSolved; + + if (!freedomReached && nAstroPSolved) { - if((obsStar-counterStarObs)<=isConstraint) - { //constraint - matrixIndex[ii*multMI+(multMI-1)]=offsetAttParam; - constraintFound[counterConstr][0]=currentStar/1000; - constraintFound[counterConstr][1]=rowInFile; + if ((obsStar - counterStarObs) <= isConstraint) + { //constraint + matrixIndex[ii * multMI + (multMI - 1)] = offsetAttParam; + constraintFound[counterConstr][0] = currentStar / 1000; + constraintFound[counterConstr][1] = rowInFile; counterConstr++; - - if(counterConstr==MAX_CONSTR){ - printf("PE=%d Abort increase MAX_CONSTR and recompile =%d \n",myid,counterConstr); - MPI_Abort(MPI_COMM_WORLD,1); + + if (counterConstr == MAX_CONSTR) + { + printf("PE=%d Abort increase MAX_CONSTR and recompile =%d \n", myid, counterConstr); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } } - else{ - if(lastFreedom>=nDegFreedomAtt-nAttParAxis) lastFreedom=nDegFreedomAtt-nAttParAxis; - matrixIndex[ii*multMI+(multMI-1)]=offsetAttParam+lastFreedom; - if(lastFreedom>=endFreedom || lastFreedom>=nDegFreedomAtt-nAttParAxis) freedomReached=1; - lastFreedom+=nAttParAxis; + else + { + if (lastFreedom >= nDegFreedomAtt - nAttParAxis) + lastFreedom = nDegFreedomAtt - nAttParAxis; + matrixIndex[ii * multMI + (multMI - 1)] = offsetAttParam + lastFreedom; + if (lastFreedom >= endFreedom || lastFreedom >= nDegFreedomAtt - nAttParAxis) + freedomReached = 1; + lastFreedom += nAttParAxis; } - } else { - lastFreedom=( ( (double)rand() ) / ( ((double)RAND_MAX) ) ) * (nDegFreedomAtt-nAttParAxis+1); - if(lastFreedom>nDegFreedomAtt-nAttParAxis) lastFreedom=nDegFreedomAtt-nAttParAxis; - if((obsStar-counterStarObs)<=isConstraint) //constraint + } + else + { + lastFreedom = (((double)rand()) / (((double)RAND_MAX))) * (nDegFreedomAtt - nAttParAxis + 1); + if (lastFreedom > nDegFreedomAtt - nAttParAxis) + lastFreedom = nDegFreedomAtt - nAttParAxis; + if ((obsStar - counterStarObs) <= isConstraint) //constraint { - lastFreedom=0; - constraintFound[counterConstr][0]=currentStar/1000; - constraintFound[counterConstr][1]=rowInFile; + lastFreedom = 0; + constraintFound[counterConstr][0] = currentStar / 1000; + constraintFound[counterConstr][1] = rowInFile; counterConstr++; } - matrixIndex[ii*multMI+(multMI-1)]=offsetAttParam+lastFreedom; + matrixIndex[ii * multMI + (multMI - 1)] = offsetAttParam + lastFreedom; } ///////////// generate InstrIndex - - if(!instrFreedomReached && nInstrPSolved) - { - if((obsStar-counterStarObs)<=isConstraint) - { //constraint - for(int kk=0;kk<nInstrPSolved;kk++) - instrCol[ii*nInstrPSolved+kk]=0; - } - else{ - if(instrLastFreedom>instrEndFreedom) instrLastFreedom=instrEndFreedom; - instrCol[ii*nInstrPSolved]=instrLastFreedom; - for(int kk=1;kk<nInstrPSolved;kk++) - instrCol[ii*nInstrPSolved+kk]=(((double)rand()) / (((double)RAND_MAX))) * (nInstrParam-1); - if(instrLastFreedom==instrEndFreedom) - instrFreedomReached=1; + + if (!instrFreedomReached && nInstrPSolved) + { + if ((obsStar - counterStarObs) <= isConstraint) + { //constraint + for (int kk = 0; kk < nInstrPSolved; kk++) + instrCol[ii * nInstrPSolved + kk] = 0; + } + else + { + if (instrLastFreedom > instrEndFreedom) + instrLastFreedom = instrEndFreedom; + instrCol[ii * nInstrPSolved] = instrLastFreedom; + for (int kk = 1; kk < nInstrPSolved; kk++) + instrCol[ii * nInstrPSolved + kk] = (((double)rand()) / (((double)RAND_MAX))) * (nInstrParam - 1); + if (instrLastFreedom == instrEndFreedom) + instrFreedomReached = 1; instrLastFreedom++; } - } else { - if((obsStar-counterStarObs)<=isConstraint) + } + else + { + if ((obsStar - counterStarObs) <= isConstraint) { //constraint - for(int kk=0;kk<nInstrPSolved;kk++) - instrCol[ii*nInstrPSolved+kk]=0; - }else{ - for(int kk=0;kk<nInstrPSolved;kk++) - instrCol[ii*nInstrPSolved+kk]=(((double)rand() ) / ( ((double)RAND_MAX) ) ) * (nInstrParam-1); + for (int kk = 0; kk < nInstrPSolved; kk++) + instrCol[ii * nInstrPSolved + kk] = 0; + } + else + { + for (int kk = 0; kk < nInstrPSolved; kk++) + instrCol[ii * nInstrPSolved + kk] = (((double)rand()) / (((double)RAND_MAX))) * (nInstrParam - 1); } } ///////////// generate systemMatrix - if((obsStar-counterStarObs)>isConstraint ) - { - for(int q=0;q<nAstroPSolved;q++) - systemMatrix[ii*nparam+q]=(((double)rand())/RAND_MAX)*2 - 1.0; - for(int q=0;q<nAttP+nInstrPSolved+nGlobP;q++) - systemMatrix[ii*nparam+nAstroPSolved+q]=(((double)rand())/RAND_MAX)*2 - 1.0; - } else // I add a Constraint - { - for(int q=0;q<nAstroPSolved+nAttP+nInstrPSolved+nGlobP;q++) - systemMatrix[ii*nparam+q]=0.; - if(nAstroPSolved>0) - { - if(ii!=0) offsetConstraint=0; - int foundedConstraint=(obsStar-counterStarObs)+offsetConstraint; - int itis=0; - for(int q=0;q<nConstrLong;q++) - if(constrLongId[q]==currentStar){ + if ((obsStar - counterStarObs) > isConstraint) + { + for (int q = 0; q < nAstroPSolved; q++) + systemMatrix[ii * nparam + q] = (((double)rand()) / RAND_MAX) * 2 - 1.0; + for (int q = 0; q < nAttP + nInstrPSolved + nGlobP; q++) + systemMatrix[ii * nparam + nAstroPSolved + q] = (((double)rand()) / RAND_MAX) * 2 - 1.0; + } + else // I add a Constraint + { + for (int q = 0; q < nAstroPSolved + nAttP + nInstrPSolved + nGlobP; q++) + systemMatrix[ii * nparam + q] = 0.; + if (nAstroPSolved > 0) + { + if (ii != 0) + offsetConstraint = 0; + int foundedConstraint = (obsStar - counterStarObs) + offsetConstraint; + int itis = 0; + for (int q = 0; q < nConstrLong; q++) + if (constrLongId[q] == currentStar) + { itis++; - if(itis==foundedConstraint) - systemMatrix[ii*nparam+LongPos]=constrLongW[q]; + if (itis == foundedConstraint) + systemMatrix[ii * nparam + LongPos] = constrLongW[q]; } - for(int q=0;q<nConstrLat;q++) - if(constrLatId[q]==currentStar){ + for (int q = 0; q < nConstrLat; q++) + if (constrLatId[q] == currentStar) + { itis++; - if(itis==foundedConstraint) - systemMatrix[ii*nparam+LatPos]=constrLatW[q]; + if (itis == foundedConstraint) + systemMatrix[ii * nparam + LatPos] = constrLatW[q]; } - for(int q=0;q<nConstrMuLong;q++) - if(constrMuLongId[q]==currentStar){ + for (int q = 0; q < nConstrMuLong; q++) + if (constrMuLongId[q] == currentStar) + { itis++; - if(itis==foundedConstraint) - systemMatrix[ii*nparam+MuLongPos]=constrMuLongW[q]; + if (itis == foundedConstraint) + systemMatrix[ii * nparam + MuLongPos] = constrMuLongW[q]; } - for(int q=0;q<nConstrMuLat;q++) - if(constrMuLatId[q]==currentStar){ + for (int q = 0; q < nConstrMuLat; q++) + if (constrMuLatId[q] == currentStar) + { itis++; - if(itis==foundedConstraint) - systemMatrix[ii*nparam+MuLatPos]=constrMuLatW[q]; + if (itis == foundedConstraint) + systemMatrix[ii * nparam + MuLatPos] = constrMuLatW[q]; } } } ///////////////////////// - if((obsStar-counterStarObs)<=isConstraint ) + if ((obsStar - counterStarObs) <= isConstraint) { - printf("PE=%d isConstraint=%d ii=%ld matrixIndex[ii*2]=%ld matrixIndex[ii*2+1]=%ld\n",myid,isConstraint,ii,matrixIndex[ii*2],matrixIndex[ii*2+1]); - for(int q=0;q<nparam;q++) printf("PE=%d systemMatrix[%ld]=%lf ",myid,ii*nparam+q,systemMatrix[ii*nparam+q]); + printf("PE=%d isConstraint=%d ii=%ld matrixIndex[ii*2]=%ld matrixIndex[ii*2+1]=%ld\n", myid, isConstraint, ii, matrixIndex[ii * 2], matrixIndex[ii * 2 + 1]); + for (int q = 0; q < nparam; q++) + printf("PE=%d systemMatrix[%ld]=%lf ", myid, ii * nparam + q, systemMatrix[ii * nparam + q]); printf("\n"); } - + /////////////////// Prepare next Obs counterStarObs++; - if(counterStarObs==obsStar) + if (counterStarObs == obsStar) { - if(myid==(nproc-1)) - numOfObslast=counterStarObs; - counterStarObs=0; + if (myid == (nproc - 1)) + numOfObslast = counterStarObs; + counterStarObs = 0; currentStar++; - changedStar=1; - isConstraint=0; - obsStar=nObsxStar; - if(currentStar<nobsOri%nStar) obsStar++; - if(nConstr>0) - { - for(int q=0;q<nConstrLat;q++) - if(constrLatId[q]==currentStar) + changedStar = 1; + isConstraint = 0; + obsStar = nObsxStar; + if (currentStar < nobsOri % nStar) + obsStar++; + if (nConstr > 0) + { + for (int q = 0; q < nConstrLat; q++) + if (constrLatId[q] == currentStar) { obsStar++; isConstraint++; } - for(int q=0;q<nConstrLong;q++) - if(constrLongId[q]==currentStar) + for (int q = 0; q < nConstrLong; q++) + if (constrLongId[q] == currentStar) { obsStar++; isConstraint++; } - for(int q=0;q<nConstrMuLat;q++) - if(constrMuLatId[q]==currentStar) + for (int q = 0; q < nConstrMuLat; q++) + if (constrMuLatId[q] == currentStar) { obsStar++; isConstraint++; } - for(int q=0;q<nConstrMuLong;q++) - if(constrMuLongId[q]==currentStar) + for (int q = 0; q < nConstrMuLong; q++) + if (constrMuLongId[q] == currentStar) { obsStar++; isConstraint++; } - } } ///////////////////////////////// Filling knownTerms -1.. 1 - if(!idtest) knownTerms[ii]=(((double) rand())/RAND_MAX)*2.0-1.0; //show idtest=1 at the beginning instead of =0 + if (!idtest) + knownTerms[ii] = (((double)rand()) / RAND_MAX) * 2.0 - 1.0; //show idtest=1 at the beginning instead of =0 ///////////////////////////////////////// - - + /////////////////////////////////// } // for ii=0 mapNoss[myid] - + if (!freedomReached && !zeroAtt) { - printf("PE=%d Error ndegFreedomAtt not correctly generated\n",myid); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error ndegFreedomAtt not correctly generated\n", myid); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } if (!instrFreedomReached && !zeroInstr) { - printf("PE=%d Error instrP not all generated instrLastFreedom=%d\n",myid,instrLastFreedom); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d Error instrP not all generated instrLastFreedom=%d\n", myid, instrLastFreedom); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); - } //////////////////// ///////////////////////// generate extConstr on systemMatrix - if(extConstraint){ + if (extConstraint) + { double randVal; double *accumulator; - accumulator=(double *) calloc(nEqExtConstr,sizeof(double)); - attNS=(double *) calloc(nDegFreedomAtt,sizeof(double)); + accumulator = (double *)calloc(nEqExtConstr, sizeof(double)); + attNS = (double *)calloc(nDegFreedomAtt, sizeof(double)); if (!attNS) - exit(err_malloc("attNS",myid)); - if(myid==0){ - for(int i=0;i<nDegFreedomAtt;i++) - attNS[i]=(((double)rand())/RAND_MAX)*2 - 1.0; - } - MPI_Bcast( attNS, nDegFreedomAtt, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - for(int j=0;j<nEqExtConstr;j++){ - for(int i=0;i<addElementextStar+addElementAtt;i++){ - randVal=(((double)rand())/RAND_MAX)*2 - 1.0; - if(i<addElementextStar){ - if(nAstroPSolved==3 && i%nAstroPSolved==0) randVal=0.; - if(nAstroPSolved==4 && i%nAstroPSolved>=2) randVal=0.; - if(nAstroPSolved==5 && i%nAstroPSolved==0) randVal=0.; - if(nAstroPSolved==5 && i%nAstroPSolved>2 && j<3) randVal=0.; + exit(err_malloc("attNS", myid)); + if (myid == 0) + { + for (int i = 0; i < nDegFreedomAtt; i++) + attNS[i] = (((double)rand()) / RAND_MAX) * 2 - 1.0; + } + MPI_Bcast(attNS, nDegFreedomAtt, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + for (int j = 0; j < nEqExtConstr; j++) + { + for (int i = 0; i < addElementextStar + addElementAtt; i++) + { + randVal = (((double)rand()) / RAND_MAX) * 2 - 1.0; + if (i < addElementextStar) + { + if (nAstroPSolved == 3 && i % nAstroPSolved == 0) + randVal = 0.; + if (nAstroPSolved == 4 && i % nAstroPSolved >= 2) + randVal = 0.; + if (nAstroPSolved == 5 && i % nAstroPSolved == 0) + randVal = 0.; + if (nAstroPSolved == 5 && i % nAstroPSolved > 2 && j < 3) + randVal = 0.; } - if(i>=addElementextStar){ - if(j<3) randVal=1.0; - if(j==0 || j==3){ - if(i>=addElementextStar+addElementAtt/nAttAxes) randVal=0.0; + if (i >= addElementextStar) + { + if (j < 3) + randVal = 1.0; + if (j == 0 || j == 3) + { + if (i >= addElementextStar + addElementAtt / nAttAxes) + randVal = 0.0; } - if(j==1 || j==4){ - if(i<addElementextStar+addElementAtt/nAttAxes) randVal=0.0; - if(i>=addElementextStar+2*addElementAtt/nAttAxes) randVal=0.0; + if (j == 1 || j == 4) + { + if (i < addElementextStar + addElementAtt / nAttAxes) + randVal = 0.0; + if (i >= addElementextStar + 2 * addElementAtt / nAttAxes) + randVal = 0.0; } - if(j==2 || j==5){ - if(i<addElementextStar+2*addElementAtt/nAttAxes) randVal=0.0; + if (j == 2 || j == 5) + { + if (i < addElementextStar + 2 * addElementAtt / nAttAxes) + randVal = 0.0; } - - } - systemMatrix[mapNcoeff[myid]+i+j*nOfElextObs]=randVal*extConstrW; - accumulator[j]+=randVal*extConstrW; - + systemMatrix[mapNcoeff[myid] + i + j * nOfElextObs] = randVal * extConstrW; + accumulator[j] += randVal * extConstrW; } - if(!idtest) - knownTerms[mapNoss[myid]+j]=0.; - }// j=0 - if(idtest) + if (!idtest) + knownTerms[mapNoss[myid] + j] = 0.; + } // j=0 + if (idtest) MPI_Allreduce(accumulator, &knownTerms[mapNoss[myid]], nEqExtConstr, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); free(accumulator); } //if(extConstr - + ///////////////////////// generate barConstr on systemMatrix - if(barConstraint){ + if (barConstraint) + { double randVal; double *accumulator; - accumulator=(double *) calloc(nEqBarConstr,sizeof(double)); - - for(int j=0;j<nEqBarConstr;j++){ - for(int i=0;i<addElementbarStar;i++){ - randVal=(((double)rand())/RAND_MAX)*2 - 1.0; - if(nAstroPSolved==3 && i%nAstroPSolved==0) randVal=0.; - if(nAstroPSolved==4 && i%nAstroPSolved>=2) randVal=0.; - if(nAstroPSolved==5 && i%nAstroPSolved==0) randVal=0.; - if(nAstroPSolved==5 && i%nAstroPSolved>2 && j<3) randVal=0.; - systemMatrix[mapNcoeff[myid]+nEqExtConstr*nOfElextObs+i+j*nOfElBarObs]=randVal*barConstrW; - accumulator[j]+=randVal*barConstrW; - - } - if(!idtest) - knownTerms[mapNoss[myid]+nEqExtConstr+j]=0.; - }// j=0 - if(idtest) - MPI_Allreduce(accumulator, &knownTerms[mapNoss[myid]+nEqExtConstr], nEqBarConstr, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + accumulator = (double *)calloc(nEqBarConstr, sizeof(double)); + + for (int j = 0; j < nEqBarConstr; j++) + { + for (int i = 0; i < addElementbarStar; i++) + { + randVal = (((double)rand()) / RAND_MAX) * 2 - 1.0; + if (nAstroPSolved == 3 && i % nAstroPSolved == 0) + randVal = 0.; + if (nAstroPSolved == 4 && i % nAstroPSolved >= 2) + randVal = 0.; + if (nAstroPSolved == 5 && i % nAstroPSolved == 0) + randVal = 0.; + if (nAstroPSolved == 5 && i % nAstroPSolved > 2 && j < 3) + randVal = 0.; + systemMatrix[mapNcoeff[myid] + nEqExtConstr * nOfElextObs + i + j * nOfElBarObs] = randVal * barConstrW; + accumulator[j] += randVal * barConstrW; + } + if (!idtest) + knownTerms[mapNoss[myid] + nEqExtConstr + j] = 0.; + } // j=0 + if (idtest) + MPI_Allreduce(accumulator, &knownTerms[mapNoss[myid] + nEqExtConstr], nEqBarConstr, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); free(accumulator); } //if(barConstr - + ///////////////////////// generate instrConstr on systemMatrix // There are 1 AL + 2 AC constraint equations for each time interval for the large scale parameters (total=3*nTimeIntervals) // There are 1 AL + 1 AC constraint equations for each CCD and Legendre polinomial degree (total=2*nCCDs*3) // The equations are described by three arrays: instrCoeffConstr, instrColsConstr, instrConstrIlung, which contain the // coefficients, the column indexes and the length of the non-zero coefficients of each equation respectively. - comlsqr.offsetCMag=maInstrFlag*nCCDs; // offest=0 if maInstrFlag=0 - comlsqr.offsetCnu=comlsqr.offsetCMag+nuInstrFlag*nFoVs*nCCDs; // offest=offsetCMag if nuInstrFlag=0 - comlsqr.offsetCdelta_eta=comlsqr.offsetCnu+ssInstrFlag*nCCDs*nPixelColumns; // offest=offsetCnu if ssInstrFlag=0 - comlsqr.offsetCDelta_eta_1=comlsqr.offsetCdelta_eta+lsInstrFlag*nFoVs*nCCDs*nTimeIntervals; - comlsqr.offsetCDelta_eta_2=comlsqr.offsetCdelta_eta+lsInstrFlag*2*nFoVs*nCCDs*nTimeIntervals; - comlsqr.offsetCDelta_eta_3=comlsqr.offsetCdelta_eta+lsInstrFlag*3*nFoVs*nCCDs*nTimeIntervals; - comlsqr.offsetCdelta_zeta=comlsqr.offsetCDelta_eta_3+ssInstrFlag*nCCDs*nPixelColumns; - comlsqr.offsetCDelta_zeta_1=comlsqr.offsetCdelta_zeta+lsInstrFlag*nFoVs*nCCDs*nTimeIntervals; - comlsqr.offsetCDelta_zeta_2=comlsqr.offsetCdelta_zeta+lsInstrFlag*2*nFoVs*nCCDs*nTimeIntervals; - comlsqr.nInstrPSolved=nInstrPSolved; - - - if(myid==0 && lsInstrFlag && nElemIC!=0 ){ - double * instrCoeffConstr; - instrCoeffConstr=(double *) calloc(nElemIC, sizeof(double)); - int * instrColsConstr; - instrColsConstr=(int *) calloc(nElemIC, sizeof(int)); - - if(!computeInstrConstr(comlsqr, instrCoeffConstr, instrColsConstr, instrConstrIlung)) + comlsqr.offsetCMag = maInstrFlag * nCCDs; // offest=0 if maInstrFlag=0 + comlsqr.offsetCnu = comlsqr.offsetCMag + nuInstrFlag * nFoVs * nCCDs; // offest=offsetCMag if nuInstrFlag=0 + comlsqr.offsetCdelta_eta = comlsqr.offsetCnu + ssInstrFlag * nCCDs * nPixelColumns; // offest=offsetCnu if ssInstrFlag=0 + comlsqr.offsetCDelta_eta_1 = comlsqr.offsetCdelta_eta + lsInstrFlag * nFoVs * nCCDs * nTimeIntervals; + comlsqr.offsetCDelta_eta_2 = comlsqr.offsetCdelta_eta + lsInstrFlag * 2 * nFoVs * nCCDs * nTimeIntervals; + comlsqr.offsetCDelta_eta_3 = comlsqr.offsetCdelta_eta + lsInstrFlag * 3 * nFoVs * nCCDs * nTimeIntervals; + comlsqr.offsetCdelta_zeta = comlsqr.offsetCDelta_eta_3 + ssInstrFlag * nCCDs * nPixelColumns; + comlsqr.offsetCDelta_zeta_1 = comlsqr.offsetCdelta_zeta + lsInstrFlag * nFoVs * nCCDs * nTimeIntervals; + comlsqr.offsetCDelta_zeta_2 = comlsqr.offsetCdelta_zeta + lsInstrFlag * 2 * nFoVs * nCCDs * nTimeIntervals; + comlsqr.nInstrPSolved = nInstrPSolved; + + if (myid == 0 && lsInstrFlag && nElemIC != 0) + { + double *instrCoeffConstr; + instrCoeffConstr = (double *)calloc(nElemIC, sizeof(double)); + int *instrColsConstr; + instrColsConstr = (int *)calloc(nElemIC, sizeof(int)); + + if (!computeInstrConstr(comlsqr, instrCoeffConstr, instrColsConstr, instrConstrIlung)) { printf("SEVERE ERROR PE=0 computeInstrConstr failed\n"); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } ////////////////////////// - for(int k=0;k<nElemIC;k++) - instrCoeffConstr[k]=instrCoeffConstr[k]*wgInstrCoeff; + for (int k = 0; k < nElemIC; k++) + instrCoeffConstr[k] = instrCoeffConstr[k] * wgInstrCoeff; ///////////////////////// - for(int j=0;j<nElemIC;j++){ - systemMatrix[mapNcoeff[myid]+nOfElextObs*nEqExtConstr+nOfElBarObs*nEqBarConstr+j]=instrCoeffConstr[j]; - instrCol[mapNoss[myid]*nInstrPSolved+j]=instrColsConstr[j]; - } - int counter0=0; - for(int j=0;j<nOfInstrConstr;j++){ - double sumVal=0.; - for(int k=0;k<instrConstrIlung[j];k++){ - sumVal+= systemMatrix[mapNcoeff[myid]+nOfElextObs*nEqExtConstr+nOfElBarObs*nEqBarConstr+counter0]; + for (int j = 0; j < nElemIC; j++) + { + systemMatrix[mapNcoeff[myid] + nOfElextObs * nEqExtConstr + nOfElBarObs * nEqBarConstr + j] = instrCoeffConstr[j]; + instrCol[mapNoss[myid] * nInstrPSolved + j] = instrColsConstr[j]; + } + int counter0 = 0; + for (int j = 0; j < nOfInstrConstr; j++) + { + double sumVal = 0.; + for (int k = 0; k < instrConstrIlung[j]; k++) + { + sumVal += systemMatrix[mapNcoeff[myid] + nOfElextObs * nEqExtConstr + nOfElBarObs * nEqBarConstr + counter0]; counter0++; } - if(idtest){ - knownTerms[mapNoss[myid]+nEqExtConstr+nEqBarConstr+j]=sumVal; - } else{ - knownTerms[mapNoss[myid]+nEqExtConstr+nEqBarConstr+j]=0.; + if (idtest) + { + knownTerms[mapNoss[myid] + nEqExtConstr + nEqBarConstr + j] = sumVal; + } + else + { + knownTerms[mapNoss[myid] + nEqExtConstr + nEqBarConstr + j] = 0.; } } - if(counter0 != nElemIC){ - printf("SEVERE ERROR PE=0 counter0=%d != nElemIC=%d when computing knownTerms for InstrConstr\n",counter0,nElemIC); - MPI_Abort(MPI_COMM_WORLD,1); + if (counter0 != nElemIC) + { + printf("SEVERE ERROR PE=0 counter0=%d != nElemIC=%d when computing knownTerms for InstrConstr\n", counter0, nElemIC); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } //..... write files - if(wrFilebin){ + if (wrFilebin) + { chdir(wpath); chdir(wrfileDir); - FILE *fpICCoeff,*fpICCols,*fpICIlung; - fpICCoeff=fopen("instrConstrRows_Coeff.bin","wb"); - fpICCols=fopen("instrConstrRows_Cols.bin","wb"); - fpICIlung=fopen("instrConstrRows_Ilung.bin","wb"); - - fwrite(instrConstrIlung,sizeof(int),nOfInstrConstr,fpICIlung); - fwrite(instrCoeffConstr,sizeof(double),nElemIC,fpICCoeff); - fwrite(instrColsConstr,sizeof(int),nElemIC,fpICCols); - + FILE *fpICCoeff, *fpICCols, *fpICIlung; + fpICCoeff = fopen("instrConstrRows_Coeff.bin", "wb"); + fpICCols = fopen("instrConstrRows_Cols.bin", "wb"); + fpICIlung = fopen("instrConstrRows_Ilung.bin", "wb"); + + fwrite(instrConstrIlung, sizeof(int), nOfInstrConstr, fpICIlung); + fwrite(instrCoeffConstr, sizeof(double), nElemIC, fpICCoeff); + fwrite(instrColsConstr, sizeof(int), nElemIC, fpICCols); + fclose(fpICCoeff); fclose(fpICCols); fclose(fpICIlung); @@ -2102,42 +2413,44 @@ int main(int argc, char **argv) { } free(instrCoeffConstr); free(instrColsConstr); - } // if(myid==0) - MPI_Bcast(&systemMatrix[mapNcoeff[myid]+nOfElextObs*nEqExtConstr+nOfElBarObs*nEqBarConstr], nElemIC, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&instrCol[mapNoss[myid]*nInstrPSolved], nElemIC, MPI_INT, 0, MPI_COMM_WORLD); + } // if(myid==0) + MPI_Bcast(&systemMatrix[mapNcoeff[myid] + nOfElextObs * nEqExtConstr + nOfElBarObs * nEqBarConstr], nElemIC, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&instrCol[mapNoss[myid] * nInstrPSolved], nElemIC, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(instrConstrIlung, nOfInstrConstr, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&knownTerms[mapNoss[myid]+nEqExtConstr+nEqBarConstr], nOfInstrConstr, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&knownTerms[mapNoss[myid] + nEqExtConstr + nEqBarConstr], nOfInstrConstr, MPI_DOUBLE, 0, MPI_COMM_WORLD); /////// Search for map - if(nAstroPSolved) + if (nAstroPSolved) { - firstStar=matrixIndex[0]/nAstroPSolved; - lastStar=matrixIndex[mapNoss[myid]*2-2]/nAstroPSolved; - seqStar=lastStar-firstStar+1; + firstStar = matrixIndex[0] / nAstroPSolved; + lastStar = matrixIndex[mapNoss[myid] * 2 - 2] / nAstroPSolved; + seqStar = lastStar - firstStar + 1; } - else{ - firstStar=0; - lastStar=0; + else + { + firstStar = 0; + lastStar = 0; } - if(extConstraint && (firstStar!=firstStarConstr || lastStar!=lastStarConstr+starOverlap)){ - printf("PE=%d Error extConstraint: firstStar=%ld firstStarConstr=%ld lastStar=%ld lastStarConstr=%ld\n",myid,firstStar,firstStarConstr,lastStar,lastStarConstr); - MPI_Abort(MPI_COMM_WORLD,1); + if (extConstraint && (firstStar != firstStarConstr || lastStar != lastStarConstr + starOverlap)) + { + printf("PE=%d Error extConstraint: firstStar=%ld firstStarConstr=%ld lastStar=%ld lastStarConstr=%ld\n", myid, firstStar, firstStarConstr, lastStar, lastStarConstr); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); - } - if(barConstraint && (firstStar!=firstStarConstr || lastStar!=lastStarConstr+starOverlap)){ - printf("PE=%d Error barConstraint: firstStar=%ld firstStarConstr=%ld lastStar=%ld lastStarConstr=%ld\n",myid,firstStar,firstStarConstr,lastStar,lastStarConstr); - MPI_Abort(MPI_COMM_WORLD,1); + if (barConstraint && (firstStar != firstStarConstr || lastStar != lastStarConstr + starOverlap)) + { + printf("PE=%d Error barConstraint: firstStar=%ld firstStarConstr=%ld lastStar=%ld lastStarConstr=%ld\n", myid, firstStar, firstStarConstr, lastStar, lastStarConstr); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); - } - + /////////////////////////////////////////////////////// - + //////////////////////////////////////////////////////////////////// chdir(wpath); - if(outputDirOpt) chdir(outputDir); // go to output dir - + if (outputDirOpt) + chdir(outputDir); // go to output dir + //////////// Identity solution test // There are two possible IDtest modes: compatible and incompatible. // * in "compatible" mode the known term read from the input file is substituted by @@ -2154,402 +2467,426 @@ int main(int argc, char **argv) { // (i.e. the sum of the coefficients since we are in IDtest mode). Therefore the // perturbed known term is computed as // KT_perturbed = KT_unperturbed*(1+x) - - - if(idtest) //if Identity test, overwrite the value of the knownterm + + if (idtest) //if Identity test, overwrite the value of the knownterm { - for(ii=0;ii<mapNoss[myid];ii++) + for (ii = 0; ii < mapNoss[myid]; ii++) { - knownTerms[ii]=0.; - for(jj=0;jj<nparam;jj++) - knownTerms[ii] += systemMatrix[ii*nparam+jj]; + knownTerms[ii] = 0.; + for (jj = 0; jj < nparam; jj++) + knownTerms[ii] += systemMatrix[ii * nparam + jj]; } - if(srIDtest!=0.) + if (srIDtest != 0.) { - for(ii=0;ii<mapNoss[myid];ii++) + for (ii = 0; ii < mapNoss[myid]; ii++) { pert = gauss(0.0, srIDtest, idum); - knownTerms[ii] *= (1.0+pert); + knownTerms[ii] *= (1.0 + pert); } } - } ////////////////////////////////////// - endTime=MPI_Wtime(); - timeToReadFiles=MPI_Wtime()-timeToReadFiles; - printf("PE=%d time seconds=%lf to set system coefficients\n",myid, timeToReadFiles); + endTime = MPI_Wtime(); + timeToReadFiles = MPI_Wtime() - timeToReadFiles; + printf("PE=%d time seconds=%lf to set system coefficients\n", myid, timeToReadFiles); ///// check, Fix map and dim - if(seqStar<=1 && nAstroPSolved>0) + if (seqStar <= 1 && nAstroPSolved > 0) { - printf("ERROR PE=%d Only %d star Run not allowed with this PE numbers .n",myid,seqStar); + printf("ERROR PE=%d Only %d star Run not allowed with this PE numbers .n", myid, seqStar); exit(EXIT_FAILURE); } - comlsqr.VrIdAstroPDim=seqStar; - long tempDimMax=comlsqr.VrIdAstroPDim; + comlsqr.VrIdAstroPDim = seqStar; + long tempDimMax = comlsqr.VrIdAstroPDim; long tempVrIdAstroPDimMax; - MPI_Allreduce(&tempDimMax,&tempVrIdAstroPDimMax,1,MPI_LONG,MPI_MAX,MPI_COMM_WORLD); - - comlsqr.VrIdAstroPDimMax=tempVrIdAstroPDimMax; - + MPI_Allreduce(&tempDimMax, &tempVrIdAstroPDimMax, 1, MPI_LONG, MPI_MAX, MPI_COMM_WORLD); + + comlsqr.VrIdAstroPDimMax = tempVrIdAstroPDimMax; + int **tempStarSend, **tempStarRecv; - tempStarSend=(int **) calloc(nproc,sizeof(int *)); - for(int i=0;i<nproc;i++) - tempStarSend[i]=(int *) calloc(2,sizeof(int)); - tempStarRecv=(int **) calloc(nproc,sizeof(int *)); - for(int i=0;i<nproc;i++) - tempStarRecv[i]=(int *) calloc(2,sizeof(int)); - + tempStarSend = (int **)calloc(nproc, sizeof(int *)); + for (int i = 0; i < nproc; i++) + tempStarSend[i] = (int *)calloc(2, sizeof(int)); + tempStarRecv = (int **)calloc(nproc, sizeof(int *)); + for (int i = 0; i < nproc; i++) + tempStarRecv[i] = (int *)calloc(2, sizeof(int)); + int *testVectSend, *testVectRecv; - testVectSend=(int *) calloc(2*nproc,sizeof(int)); - testVectRecv=(int *) calloc(2*nproc,sizeof(int)); - testVectSend[2*myid]=firstStar; - testVectSend[2*myid+1]=lastStar; - - MPI_Allreduce(testVectSend,testVectRecv,2*nproc,MPI_INT,MPI_SUM,MPI_COMM_WORLD); - - - comlsqr.mapStar=(int **) calloc(nproc,sizeof(int *)); - for(int i=0;i<nproc;i++) - comlsqr.mapStar[i]=(int *) calloc(2,sizeof(int)); - for(int i=0;i<nproc;i++) - { - comlsqr.mapStar[i][0]=testVectRecv[2*i]; - comlsqr.mapStar[i][1]=testVectRecv[2*i+1]; - } - - - for(int i=0;i<nproc;i++) { + testVectSend = (int *)calloc(2 * nproc, sizeof(int)); + testVectRecv = (int *)calloc(2 * nproc, sizeof(int)); + testVectSend[2 * myid] = firstStar; + testVectSend[2 * myid + 1] = lastStar; + + MPI_Allreduce(testVectSend, testVectRecv, 2 * nproc, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + + comlsqr.mapStar = (int **)calloc(nproc, sizeof(int *)); + for (int i = 0; i < nproc; i++) + comlsqr.mapStar[i] = (int *)calloc(2, sizeof(int)); + for (int i = 0; i < nproc; i++) + { + comlsqr.mapStar[i][0] = testVectRecv[2 * i]; + comlsqr.mapStar[i][1] = testVectRecv[2 * i + 1]; + } + + for (int i = 0; i < nproc; i++) + { free(tempStarSend[i]); free(tempStarRecv[i]); } - + free(tempStarSend); free(tempStarRecv); - - if(comlsqr.mapStar[myid][0]==comlsqr.mapStar[myid][1] && nAstroPSolved>0) + + if (comlsqr.mapStar[myid][0] == comlsqr.mapStar[myid][1] && nAstroPSolved > 0) { - printf("PE=%d ERROR. Only one star in this PE: starting star=%d ending start=%d\n",myid,comlsqr.mapStar[myid][0],comlsqr.mapStar[myid][1]); - MPI_Abort(MPI_COMM_WORLD,1); + printf("PE=%d ERROR. Only one star in this PE: starting star=%d ending start=%d\n", myid, comlsqr.mapStar[myid][0], comlsqr.mapStar[myid][1]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); - } - if(myid==0) - for(int i=0;i<nproc;i++)printf("mapStar[%d][0]=%d mapStar[%d][1]=%d\n",i,comlsqr.mapStar[i][0],i,comlsqr.mapStar[i][1]); - - - - //////// Check Null Space Vector - if(extConstraint){ + if (myid == 0) + for (int i = 0; i < nproc; i++) + printf("mapStar[%d][0]=%d mapStar[%d][1]=%d\n", i, comlsqr.mapStar[i][0], i, comlsqr.mapStar[i][1]); + + //////// Check Null Space Vector + if (extConstraint) + { seconds[4] = time(NULL); - - nullSpaceCk=cknullSpace(systemMatrix,matrixIndex,attNS,comlsqr); - if(myid==0){ + + nullSpaceCk = cknullSpace(systemMatrix, matrixIndex, attNS, comlsqr); + if (myid == 0) + { printf("NullSpace check\n"); - for(int j=0;j<nEqExtConstr;j++) - printf("Eq. Constraint %d: Norm=%15.7f Min=%15.7f Max=%15.7f Avg=%15.7f Var=%15.7f\n",j,nullSpaceCk.vectNorm[j],nullSpaceCk.compMin[j],nullSpaceCk.compMax[j],nullSpaceCk.compAvg[j],nullSpaceCk.compVar[j]); + for (int j = 0; j < nEqExtConstr; j++) + printf("Eq. Constraint %d: Norm=%15.7f Min=%15.7f Max=%15.7f Avg=%15.7f Var=%15.7f\n", j, nullSpaceCk.vectNorm[j], nullSpaceCk.compMin[j], nullSpaceCk.compMax[j], nullSpaceCk.compAvg[j], nullSpaceCk.compVar[j]); } seconds[5] = time(NULL); tot_sec[4] = seconds[5] - seconds[4]; - if(myid==0) printf("Time to check nullspace: %ld\n", tot_sec[4]); + if (myid == 0) + printf("Time to check nullspace: %ld\n", tot_sec[4]); free(attNS); } //////// WRITE BIN FILES and FileConstr_GsrSolProps.dat ////////// - if(wrFilebin){ - if(myid==0) printf("Writing bin files...\n"); - writeBinFiles(systemMatrix,matrixIndex,instrCol,knownTerms,wrfileDir,wpath,comlsqr,debugMode); + if (wrFilebin) + { + if (myid == 0) + printf("Writing bin files...\n"); + writeBinFiles(systemMatrix, matrixIndex, instrCol, knownTerms, wrfileDir, wpath, comlsqr, debugMode); MPI_Barrier(MPI_COMM_WORLD); - if(myid==0) printf(" finished."); - - if(myid==0){ - FILE* fpFilePosConstr; + if (myid == 0) + printf(" finished."); + + if (myid == 0) + { + FILE *fpFilePosConstr; MPI_Status statusMpi; chdir(wpath); chdir(wrfileDir); - int fileNum=-1; + int fileNum = -1; int nFiles; nFiles = scandir(".", &namelistMI, selMI, alphasort); - if(debugMode) - for(ii=0;ii<nFiles ;ii++){ - printf("%s\n",namelistMI[ii]->d_name); + if (debugMode) + for (ii = 0; ii < nFiles; ii++) + { + printf("%s\n", namelistMI[ii]->d_name); } - if(nFiles <=0) + if (nFiles <= 0) { - printf("error on scandir n=%d\n",nFiles); - MPI_Abort(MPI_COMM_WORLD,1); + printf("error on scandir n=%d\n", nFiles); + MPI_Abort(MPI_COMM_WORLD, 1); } - + ////////////////// Writing FileConstr_GsrSolProps.dat - char fileConstr[512]=""; + char fileConstr[512] = ""; strcat(fileConstr, "FileConstr_"); strcat(fileConstr, filenameSolProps); - fpFilePosConstr=fopen(fileConstr,"w"); - for(int k=0;k<counterConstr;k++){ - fileNum=constraintFound[k][0]; - fprintf(fpFilePosConstr,"%d %s %d\n", fileNum, namelistMI[fileNum]->d_name,constraintFound[k][1]); - } - if(debugMode) - for(int k=0;k<counterConstr;k++){ - fileNum=constraintFound[k][0]; - printf("PE=%d %d %s %d\n",myid, fileNum, namelistMI[fileNum]->d_name,constraintFound[k][1]); + fpFilePosConstr = fopen(fileConstr, "w"); + for (int k = 0; k < counterConstr; k++) + { + fileNum = constraintFound[k][0]; + fprintf(fpFilePosConstr, "%d %s %d\n", fileNum, namelistMI[fileNum]->d_name, constraintFound[k][1]); + } + if (debugMode) + for (int k = 0; k < counterConstr; k++) + { + fileNum = constraintFound[k][0]; + printf("PE=%d %d %s %d\n", myid, fileNum, namelistMI[fileNum]->d_name, constraintFound[k][1]); } - for(int np=1;np<nproc;np++){ - MPI_Recv(&counterConstr, 1, MPI_INT, np, 0, MPI_COMM_WORLD,&statusMpi); - MPI_Recv(&constraintFound[0][0], counterConstr*2, MPI_INT, np, 1, MPI_COMM_WORLD,&statusMpi); - - for(int k=0;k<counterConstr;k++){ - fileNum=constraintFound[k][0]; - fprintf(fpFilePosConstr,"%d %s %d\n", fileNum, namelistMI[fileNum]->d_name,constraintFound[k][1]); + for (int np = 1; np < nproc; np++) + { + MPI_Recv(&counterConstr, 1, MPI_INT, np, 0, MPI_COMM_WORLD, &statusMpi); + MPI_Recv(&constraintFound[0][0], counterConstr * 2, MPI_INT, np, 1, MPI_COMM_WORLD, &statusMpi); + + for (int k = 0; k < counterConstr; k++) + { + fileNum = constraintFound[k][0]; + fprintf(fpFilePosConstr, "%d %s %d\n", fileNum, namelistMI[fileNum]->d_name, constraintFound[k][1]); } - if(debugMode) - for(int k=0;k<counterConstr;k++){ - fileNum=constraintFound[k][0]; - printf("PE=%d %d %s %d\n",np, fileNum, namelistMI[fileNum]->d_name,constraintFound[k][1]); + if (debugMode) + for (int k = 0; k < counterConstr; k++) + { + fileNum = constraintFound[k][0]; + printf("PE=%d %d %s %d\n", np, fileNum, namelistMI[fileNum]->d_name, constraintFound[k][1]); } } fclose(fpFilePosConstr); - } else { + } + else + { MPI_Send(&counterConstr, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); - MPI_Send(&constraintFound[0][0], counterConstr*2, MPI_INT, 0, 1, MPI_COMM_WORLD); - } - } - - VrIdAstroPDimMax=comlsqr.VrIdAstroPDimMax; - VrIdAstroPDim=comlsqr.VrIdAstroPDim; - VroffsetAttParam = VrIdAstroPDimMax*nAstroPSolved; - comlsqr.VroffsetAttParam=VroffsetAttParam; - - nunkSplit = VrIdAstroPDimMax*nAstroPSolved + nAttParam + nInstrParam + nGlobalParam; - comlsqr.nunkSplit=nunkSplit; - nElements = nunkSplit ; - preCondVect = (double *) calloc(nElements,sizeof(double)); + MPI_Send(&constraintFound[0][0], counterConstr * 2, MPI_INT, 0, 1, MPI_COMM_WORLD); + } + } + + VrIdAstroPDimMax = comlsqr.VrIdAstroPDimMax; + VrIdAstroPDim = comlsqr.VrIdAstroPDim; + VroffsetAttParam = VrIdAstroPDimMax * nAstroPSolved; + comlsqr.VroffsetAttParam = VroffsetAttParam; + + nunkSplit = VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam + nGlobalParam; + comlsqr.nunkSplit = nunkSplit; + nElements = nunkSplit; + preCondVect = (double *)calloc(nElements, sizeof(double)); if (!preCondVect) - exit(err_malloc("preCondVect",myid)); - totmem += nElements*sizeof(double); - + exit(err_malloc("preCondVect", myid)); + totmem += nElements * sizeof(double); + nElements = nunkSplit; // the arrays v, w, x, and se require the same amount of memory (nunk * sizeof(double)) - vVect = (double *) calloc(nElements, sizeof(double)); + vVect = (double *)calloc(nElements, sizeof(double)); if (!vVect) - exit(err_malloc("vVect",myid)); - totmem += nElements* sizeof(double); - - wVect = (double *) calloc(nElements, sizeof(double)); + exit(err_malloc("vVect", myid)); + totmem += nElements * sizeof(double); + + + //vVect_aux_AttP = (double *)calloc(nAttParam + nInstrParam , sizeof(double)); + + + + wVect = (double *)calloc(nElements, sizeof(double)); if (!wVect) - exit(err_malloc("wVect",myid)); - totmem += nElements* sizeof(double); - - xSolution = (double *) calloc(nElements, sizeof(double)); + exit(err_malloc("wVect", myid)); + totmem += nElements * sizeof(double); + + xSolution = (double *)calloc(nElements, sizeof(double)); if (!xSolution) - exit(err_malloc("xSolution",myid)); - totmem += nElements* sizeof(double); - - standardError = (double *) calloc(nElements, sizeof(double)); + exit(err_malloc("xSolution", myid)); + totmem += nElements * sizeof(double); + + standardError = (double *)calloc(nElements, sizeof(double)); if (!standardError) - exit(err_malloc("standardError",myid)); - totmem += nElements* sizeof(double); - - totmem += nElements* sizeof(double); //dcopy+vAuxVect locally allocated on lsqr.c - - totmem=totmem/(1024*1024); // mem in MB - + exit(err_malloc("standardError", myid)); + totmem += nElements * sizeof(double); + + totmem += nElements * sizeof(double); //dcopy+vAuxVect locally allocated on lsqr.c + + totmem = totmem / (1024 * 1024); // mem in MB + // Compute and write the total memory allocated - if(myid==0) + if (myid == 0) { + printf("LOCAL %ld MB of memory allocated on each task.\n", totmem); - printf("TOTAL MB memory allocated= %ld\n", nproc*totmem ); + printf("TOTAL MB memory allocated= %ld\n", nproc * totmem); } - - + /////////////////////////////// - - - - + MPI_Barrier(MPI_COMM_WORLD); // Compute the preconditioning vector for the system columns - - - long int aIndex=0; + + long int aIndex = 0; long instrLongIndex[6]; - long iIelem=0; - - - - for (ii = 0; ii < mapNoss[myid]*multMI; ii=ii+multMI) - { - long int numOfStarPos=0; - if(nAstroPSolved>0) numOfStarPos=matrixIndex[ii]/nAstroPSolved; // number of star associated to matrixIndex[ii] - long int numOfAttPos=matrixIndex[ii+(multMI-1)]; - long int VrIdAstroPValue=-1; // - - VrIdAstroPValue=numOfStarPos-comlsqr.mapStar[myid][0]; - if(VrIdAstroPValue==-1) - { - printf("PE=%d ERROR. Can't find gsrId for precondvect.\n",myid); - MPI_Abort(MPI_COMM_WORLD,1); + long iIelem = 0; + + for (ii = 0; ii < mapNoss[myid] * multMI; ii = ii + multMI) + { + long int numOfStarPos = 0; + if (nAstroPSolved > 0) + numOfStarPos = matrixIndex[ii] / nAstroPSolved; // number of star associated to matrixIndex[ii] + long int numOfAttPos = matrixIndex[ii + (multMI - 1)]; + long int VrIdAstroPValue = -1; // + + VrIdAstroPValue = numOfStarPos - comlsqr.mapStar[myid][0]; + if (VrIdAstroPValue == -1) + { + printf("PE=%d ERROR. Can't find gsrId for precondvect.\n", myid); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - for(int ns=0;ns<nAstroPSolved;ns++) + for (int ns = 0; ns < nAstroPSolved; ns++) { - ncolumn=VrIdAstroPValue*nAstroPSolved+ns; + ncolumn = VrIdAstroPValue * nAstroPSolved + ns; //// // ncolumn = numOfStarPos+ns; // cancellato - if (ncolumn >= nunkSplit || ncolumn < 0 ) { - printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii]=%ld\n",myid, ncolumn, ii, + if (ncolumn >= nunkSplit || ncolumn < 0) + { + printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii]=%ld\n", myid, ncolumn, ii, matrixIndex[ii]); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; - if(preCondVect[ncolumn]==0.0) + if (preCondVect[ncolumn] == 0.0) printf("Astrometric: preCondVect[%ld]=0.0\n", ncolumn); aIndex++; } // - for(int naxis=0;naxis<nAttAxes;naxis++) - for(int ns=0;ns<nAttParAxis;ns++) + for (int naxis = 0; naxis < nAttAxes; naxis++) + for (int ns = 0; ns < nAttParAxis; ns++) { - ncolumn = numOfAttPos+(VroffsetAttParam-offsetAttParam)+ns+naxis*nDegFreedomAtt; - if (ncolumn >= nunkSplit || ncolumn < 0 ) { - printf("ERROR. PE=%d numOfAttPos=%ld nStar*nAstroPSolved=%ld ncolumn=%ld ns=%d naxis=%d matrixIndex[ii+%d]=%ld\n",myid,numOfAttPos,nStar*nAstroPSolved,ncolumn, ns, naxis,multMI-1,matrixIndex[ii+(multMI-1)]); - MPI_Abort(MPI_COMM_WORLD,1); + ncolumn = numOfAttPos + (VroffsetAttParam - offsetAttParam) + ns + naxis * nDegFreedomAtt; + if (ncolumn >= nunkSplit || ncolumn < 0) + { + printf("ERROR. PE=%d numOfAttPos=%ld nStar*nAstroPSolved=%ld ncolumn=%ld ns=%d naxis=%d matrixIndex[ii+%d]=%ld\n", myid, numOfAttPos, nStar * nAstroPSolved, ncolumn, ns, naxis, multMI - 1, matrixIndex[ii + (multMI - 1)]); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; - if(preCondVect[ncolumn]==0.0) - printf("Attitude: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n",myid, ncolumn,aIndex,systemMatrix[aIndex]); // if aggiunto + if (preCondVect[ncolumn] == 0.0) + printf("Attitude: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n", myid, ncolumn, aIndex, systemMatrix[aIndex]); // if aggiunto aIndex++; } ///// End of Attitude preCondVect - - - if(nInstrPSolved>0) + + if (nInstrPSolved > 0) { - for(int ns=0;ns<nInstrPSolved;ns++) + for (int ns = 0; ns < nInstrPSolved; ns++) { - ncolumn = offsetInstrParam+(VroffsetAttParam-offsetAttParam)+instrCol[(ii/multMI)*nInstrPSolved+ns]; - if (ncolumn >= nunkSplit || ncolumn < 0 ) + ncolumn = offsetInstrParam + (VroffsetAttParam - offsetAttParam) + instrCol[(ii / multMI) * nInstrPSolved + ns]; + if (ncolumn >= nunkSplit || ncolumn < 0) { - printf("ERROR. PE=%d ii=%ld ",myid, ii); - for(int ke=0;ke<nInstrPSolved;ke++) - printf("instrCol[%d]=%d ",ii/multMI+ke, instrCol[ii/multMI+ke]); + printf("ERROR. PE=%d ii=%ld ", myid, ii); + for (int ke = 0; ke < nInstrPSolved; ke++) + printf("instrCol[%d]=%d ", ii / multMI + ke, instrCol[ii / multMI + ke]); printf("ncolumn=%ld ns=%d\n", ncolumn, ns); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } -// if(ncolumn==55718+8000){ -// printf("OSS BEFORE aindex=%ld SM[aindex]=%f preCondVect[%ld]=%f\n",aIndex,systemMatrix[aIndex],ncolumn,preCondVect[ncolumn]); -// } + // if(ncolumn==55718+8000){ + // printf("OSS BEFORE aindex=%ld SM[aindex]=%f preCondVect[%ld]=%f\n",aIndex,systemMatrix[aIndex],ncolumn,preCondVect[ncolumn]); + // } preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; -// if(ncolumn==55718+8000){ -// printf("OSS AFTER aindex=%ld SM[aindex]=%f preCondVect[%ld]=%f\n",aIndex,systemMatrix[aIndex],ncolumn,preCondVect[ncolumn]); -// } - if(preCondVect[ncolumn]==0.0) - printf("Instrument: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n",myid, ncolumn,aIndex,systemMatrix[aIndex]);// if aggiunto + // if(ncolumn==55718+8000){ + // printf("OSS AFTER aindex=%ld SM[aindex]=%f preCondVect[%ld]=%f\n",aIndex,systemMatrix[aIndex],ncolumn,preCondVect[ncolumn]); + // } + if (preCondVect[ncolumn] == 0.0) + printf("Instrument: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n", myid, ncolumn, aIndex, systemMatrix[aIndex]); // if aggiunto aIndex++; } } ////// End of Instruments preCondVect - for(int ns=0;ns<nGlobP;ns++) + for (int ns = 0; ns < nGlobP; ns++) { - ncolumn = offsetGlobParam+(VroffsetAttParam-offsetAttParam)+ns; - if (ncolumn >= nunkSplit || ncolumn < 0 ) { - printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii+2]=%ld\n",myid, ncolumn, ii, + ncolumn = offsetGlobParam + (VroffsetAttParam - offsetAttParam) + ns; + if (ncolumn >= nunkSplit || ncolumn < 0) + { + printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii+2]=%ld\n", myid, ncolumn, ii, matrixIndex[ii]); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; - if(preCondVect[ncolumn]==0) + if (preCondVect[ncolumn] == 0) printf("Global: preCondVect[%ld]=0.0\n", ncolumn); // if aggiunto aIndex++; } } - + ///// precondvect for extConstr - if(extConstraint){ - if(aIndex!=mapNcoeff[myid]){ - printf("PE=%d. Error on aIndex=%ld different of mapNcoeff[%d]=%ld\n",myid,aIndex,myid,mapNcoeff[myid]); + if (extConstraint) + { + if (aIndex != mapNcoeff[myid]) + { + printf("PE=%d. Error on aIndex=%ld different of mapNcoeff[%d]=%ld\n", myid, aIndex, myid, mapNcoeff[myid]); MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - for(int i=0;i<nEqExtConstr;i++){ - long int numOfStarPos=0; - if(nAstroPSolved>0) numOfStarPos=firstStarConstr; // number of star associated to matrixIndex[ii] - long int numOfAttPos=startingAttColExtConstr; - long int VrIdAstroPValue=-1; // - - VrIdAstroPValue=numOfStarPos-comlsqr.mapStar[myid][0]; - if(VrIdAstroPValue==-1) - { - printf("PE=%d ERROR. Can't find gsrId for precondvect.\n",myid); - MPI_Abort(MPI_COMM_WORLD,1); + for (int i = 0; i < nEqExtConstr; i++) + { + long int numOfStarPos = 0; + if (nAstroPSolved > 0) + numOfStarPos = firstStarConstr; // number of star associated to matrixIndex[ii] + long int numOfAttPos = startingAttColExtConstr; + long int VrIdAstroPValue = -1; // + + VrIdAstroPValue = numOfStarPos - comlsqr.mapStar[myid][0]; + if (VrIdAstroPValue == -1) + { + printf("PE=%d ERROR. Can't find gsrId for precondvect.\n", myid); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - for(int ns=0;ns<nAstroPSolved*numOfExtStar;ns++) + for (int ns = 0; ns < nAstroPSolved * numOfExtStar; ns++) { - ncolumn=ns; + ncolumn = ns; //// // ncolumn = numOfStarPos+ns; // cancellato - if (ncolumn >= nunkSplit || ncolumn < 0 ) { - printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii]=%ld\n",myid, ncolumn, ii, + if (ncolumn >= nunkSplit || ncolumn < 0) + { + printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii]=%ld\n", myid, ncolumn, ii, matrixIndex[ii]); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; - if(preCondVect[ncolumn]==0.0) + if (preCondVect[ncolumn] == 0.0) printf("Astrometric: preCondVect[%ld]=0.0\n", ncolumn); aIndex++; } // - for(int naxis=0;naxis<nAttAxes;naxis++){ - for(int j=0;j<numOfExtAttCol;j++){ - ncolumn = VrIdAstroPDimMax*nAstroPSolved+startingAttColExtConstr+j+naxis*nDegFreedomAtt; - if (ncolumn >= nunkSplit || ncolumn < 0 ) { - printf("ERROR. PE=%d ncolumn=%ld naxis=%d j=%d\n",myid,ncolumn, naxis,j); - MPI_Abort(MPI_COMM_WORLD,1); + for (int naxis = 0; naxis < nAttAxes; naxis++) + { + for (int j = 0; j < numOfExtAttCol; j++) + { + ncolumn = VrIdAstroPDimMax * nAstroPSolved + startingAttColExtConstr + j + naxis * nDegFreedomAtt; + if (ncolumn >= nunkSplit || ncolumn < 0) + { + printf("ERROR. PE=%d ncolumn=%ld naxis=%d j=%d\n", myid, ncolumn, naxis, j); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; -// printf("%d %d %d %d\n",ncolumn, aIndex,j,naxis); - if(preCondVect[ncolumn]==0.0) - printf("Attitude: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n",myid, ncolumn,aIndex,systemMatrix[aIndex]); // if aggiunto - aIndex++; + preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; + // printf("%d %d %d %d\n",ncolumn, aIndex,j,naxis); + if (preCondVect[ncolumn] == 0.0) + printf("Attitude: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n", myid, ncolumn, aIndex, systemMatrix[aIndex]); // if aggiunto + aIndex++; } } } } ///// end precondvect for extConstr ///// precondvect for barConstr - if(barConstraint){ - for(int i=0;i<nEqBarConstr;i++){ - long int numOfStarPos=0; - if(nAstroPSolved>0) numOfStarPos=firstStarConstr; // number of star associated to matrixIndex[ii] - long int VrIdAstroPValue=-1; // - - VrIdAstroPValue=numOfStarPos-comlsqr.mapStar[myid][0]; - if(VrIdAstroPValue==-1) - { - printf("PE=%d ERROR. Can't find gsrId for precondvect.\n",myid); - MPI_Abort(MPI_COMM_WORLD,1); + if (barConstraint) + { + for (int i = 0; i < nEqBarConstr; i++) + { + long int numOfStarPos = 0; + if (nAstroPSolved > 0) + numOfStarPos = firstStarConstr; // number of star associated to matrixIndex[ii] + long int VrIdAstroPValue = -1; // + + VrIdAstroPValue = numOfStarPos - comlsqr.mapStar[myid][0]; + if (VrIdAstroPValue == -1) + { + printf("PE=%d ERROR. Can't find gsrId for precondvect.\n", myid); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - for(int ns=0;ns<nAstroPSolved*numOfBarStar;ns++) + for (int ns = 0; ns < nAstroPSolved * numOfBarStar; ns++) { - ncolumn=ns; + ncolumn = ns; //// // ncolumn = numOfStarPos+ns; // cancellato - if (ncolumn >= nunkSplit || ncolumn < 0 ) { - printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii]=%ld\n",myid, ncolumn, ii, + if (ncolumn >= nunkSplit || ncolumn < 0) + { + printf("ERROR. PE=%d ncolumn=%ld ii=%ld matrixIndex[ii]=%ld\n", myid, ncolumn, ii, matrixIndex[ii]); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; - if(preCondVect[ncolumn]==0.0) - printf("Astrometric: preCondVect[%ld]=0.0\n", ncolumn); + if (preCondVect[ncolumn] == 0.0) + printf("Astrometric: preCondVect[%ld]=0.0\n", ncolumn); aIndex++; } // @@ -2558,291 +2895,330 @@ int main(int argc, char **argv) { ///// end precondvect for barConstr ///// precondvect for instrConstr - if(nElemIC>0){ - for(int i=0;i<nElemIC;i++){ - ncolumn=offsetInstrParam+(VroffsetAttParam-offsetAttParam)+instrCol[mapNoss[myid]*nInstrPSolved+i]; - if (ncolumn >= nunkSplit || ncolumn < 0 ) { - printf("ERROR on instrConstr. PE=%d ncolumn=%ld i=%d\n",myid,ncolumn, i); - MPI_Abort(MPI_COMM_WORLD,1); + if (nElemIC > 0) + { + for (int i = 0; i < nElemIC; i++) + { + ncolumn = offsetInstrParam + (VroffsetAttParam - offsetAttParam) + instrCol[mapNoss[myid] * nInstrPSolved + i]; + if (ncolumn >= nunkSplit || ncolumn < 0) + { + printf("ERROR on instrConstr. PE=%d ncolumn=%ld i=%d\n", myid, ncolumn, i); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ncolumn] += systemMatrix[aIndex] * systemMatrix[aIndex]; - if(preCondVect[ncolumn]==0.0 && debugMode) - printf("Instrument: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n",myid, ncolumn,aIndex,systemMatrix[aIndex]); + if (preCondVect[ncolumn] == 0.0 && debugMode) + printf("Instrument: PE=%d preCondVect[%ld]=0.0 aIndex=%ld systemMatrix[aIndex]=%12.9lf\n", myid, ncolumn, aIndex, systemMatrix[aIndex]); aIndex++; - } } //////////////// - - + MPI_Barrier(MPI_COMM_WORLD); - + // ACCUMULATE d // double *dcopy; - dcopy=(double *)calloc(nAttParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - mpi_allreduce(&preCondVect[ VrIdAstroPDimMax*nAstroPSolved],dcopy,(long int) nAttParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - for(i=0;i<nAttParam;i++) + dcopy = (double *)calloc(nAttParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + mpi_allreduce(&preCondVect[VrIdAstroPDimMax * nAstroPSolved], dcopy, (long int)nAttParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + for (i = 0; i < nAttParam; i++) { - preCondVect[VrIdAstroPDimMax*nAstroPSolved+i]=dcopy[i]; - if(preCondVect[VrIdAstroPDimMax*nAstroPSolved+i]==0.0){ - printf("PE=%d preCondVect[%ld]=0!!\n", myid, VrIdAstroPDimMax*nAstroPSolved+i); + preCondVect[VrIdAstroPDimMax * nAstroPSolved + i] = dcopy[i]; + if (preCondVect[VrIdAstroPDimMax * nAstroPSolved + i] == 0.0) + { + printf("PE=%d preCondVect[%ld]=0!!\n", myid, VrIdAstroPDimMax * nAstroPSolved + i); } } free(dcopy); - dcopy=(double *)calloc(nInstrParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - mpi_allreduce(&preCondVect[ VrIdAstroPDimMax*nAstroPSolved+nAttParam],dcopy,(long int) nInstrParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - for(i=0;i<nInstrParam;i++) + dcopy = (double *)calloc(nInstrParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + mpi_allreduce(&preCondVect[VrIdAstroPDimMax * nAstroPSolved + nAttParam], dcopy, (long int)nInstrParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + for (i = 0; i < nInstrParam; i++) { - preCondVect[VrIdAstroPDimMax*nAstroPSolved+nAttParam+i]=dcopy[i]; - if(preCondVect[ VrIdAstroPDimMax*nAstroPSolved+nAttParam+i]==0.0) printf("PE=%d preCondVect[%d]=0!!\n", myid, i); + preCondVect[VrIdAstroPDimMax * nAstroPSolved + nAttParam + i] = dcopy[i]; + if (preCondVect[VrIdAstroPDimMax * nAstroPSolved + nAttParam + i] == 0.0) + printf("PE=%d preCondVect[%d]=0!!\n", myid, i); } free(dcopy); - dcopy=(double *)calloc(nGlobalParam,sizeof(double)); - if(!dcopy) exit(err_malloc("dcopy",myid)); - MPI_Allreduce(&preCondVect[VrIdAstroPDimMax*nAstroPSolved+nAttParam+nInstrParam],dcopy,(int) nGlobalParam,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - for(i=0;i<nGlobalParam;i++) + dcopy = (double *)calloc(nGlobalParam, sizeof(double)); + if (!dcopy) + exit(err_malloc("dcopy", myid)); + MPI_Allreduce(&preCondVect[VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam], dcopy, (int)nGlobalParam, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + for (i = 0; i < nGlobalParam; i++) { - preCondVect[VrIdAstroPDimMax*nAstroPSolved+nAttParam+nInstrParam+i]=dcopy[i]; - if(preCondVect[VrIdAstroPDimMax*nAstroPSolved+nAttParam+nInstrParam+i]==0.0) printf("PE=%d preCondVect[%d]=0!!\n", myid, i); + preCondVect[VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam + i] = dcopy[i]; + if (preCondVect[VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam + i] == 0.0) + printf("PE=%d preCondVect[%d]=0!!\n", myid, i); } free(dcopy); - if(nAstroPSolved) SumCirc(preCondVect,comlsqr); - - + if (nAstroPSolved) + SumCirc(preCondVect, comlsqr); + ////////// TEST for NO ZERO Column on A matrix - - - if(precond){ - - if(myid==0) printf("Inverting preCondVect\n"); - for (ii = 0; ii < VrIdAstroPDim*nAstroPSolved; ii++) { - if(preCondVect[ii]==0.0) - { - if(ii-VrIdAstroPDimMax*nAstroPSolved<nAttParam) - printf("ERROR Att ZERO column: PE=%d preCondVect[%ld]=0.0 AttParam=%ld \n",myid,ii, ii-VrIdAstroPDimMax*nAstroPSolved); - if(ii-VrIdAstroPDimMax*nAstroPSolved>nAttParam && ii-VrIdAstroPDimMax*nAstroPSolved<nAttParam+nInstrParam) - printf("ERROR Instr ZERO column: PE=%d preCondVect[%ld]=0.0 InstrParam=%ld \n",myid,ii, ii-(VrIdAstroPDimMax*nAstroPSolved+nAttParam)); - if(ii-VrIdAstroPDimMax*nAstroPSolved>nAttParam+nInstrParam) - printf("ERROR Global ZERO column: PE=%d preCondVect[%ld]=0.0 GlobalParam=%ld \n",myid,ii, ii-(VrIdAstroPDimMax*nAstroPSolved+nAttParam+nInstrParam)); - MPI_Abort(MPI_COMM_WORLD,1); + + if (precond) + { + + if (myid == 0) + printf("Inverting preCondVect\n"); + for (ii = 0; ii < VrIdAstroPDim * nAstroPSolved; ii++) + { + if (preCondVect[ii] == 0.0) + { + if (ii - VrIdAstroPDimMax * nAstroPSolved < nAttParam) + printf("ERROR Att ZERO column: PE=%d preCondVect[%ld]=0.0 AttParam=%ld \n", myid, ii, ii - VrIdAstroPDimMax * nAstroPSolved); + if (ii - VrIdAstroPDimMax * nAstroPSolved > nAttParam && ii - VrIdAstroPDimMax * nAstroPSolved < nAttParam + nInstrParam) + printf("ERROR Instr ZERO column: PE=%d preCondVect[%ld]=0.0 InstrParam=%ld \n", myid, ii, ii - (VrIdAstroPDimMax * nAstroPSolved + nAttParam)); + if (ii - VrIdAstroPDimMax * nAstroPSolved > nAttParam + nInstrParam) + printf("ERROR Global ZERO column: PE=%d preCondVect[%ld]=0.0 GlobalParam=%ld \n", myid, ii, ii - (VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam)); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ii] = 1.0 / sqrt(preCondVect[ii]); } - for (ii = VrIdAstroPDimMax*nAstroPSolved; ii < VrIdAstroPDimMax*nAstroPSolved + nAttParam + nInstrParam + nGlobalParam; ii++) { - if(preCondVect[ii]==0.0) + for (ii = VrIdAstroPDimMax * nAstroPSolved; ii < VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam + nGlobalParam; ii++) + { + if (preCondVect[ii] == 0.0) { - printf("ERROR non-Astrometric ZERO column: PE=%d preCondVect[%ld]=0.0\n",myid,ii); - MPI_Abort(MPI_COMM_WORLD,1); + printf("ERROR non-Astrometric ZERO column: PE=%d preCondVect[%ld]=0.0\n", myid, ii); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ii] = 1.0 / sqrt(preCondVect[ii]); } - } else{ - if(myid==0) printf("Setting preCondVect to 1.0\n"); - for (ii = 0; ii < VrIdAstroPDim*nAstroPSolved; ii++) { - if(preCondVect[ii]==0.0) + } + else + { + if (myid == 0) + printf("Setting preCondVect to 1.0\n"); + for (ii = 0; ii < VrIdAstroPDim * nAstroPSolved; ii++) + { + if (preCondVect[ii] == 0.0) { - printf("ERROR Astrometric ZERO column: PE=%d preCondVect[%ld]=0.0 Star=%ld\n",myid,ii,ii/nAstroPSolved); - MPI_Abort(MPI_COMM_WORLD,1); + printf("ERROR Astrometric ZERO column: PE=%d preCondVect[%ld]=0.0 Star=%ld\n", myid, ii, ii / nAstroPSolved); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ii] = 1.0; } - for (ii = VrIdAstroPDimMax*nAstroPSolved; ii < VrIdAstroPDimMax*nAstroPSolved + nAttParam + nInstrParam + nGlobalParam; ii++) { - if(preCondVect[ii]==0.0) + for (ii = VrIdAstroPDimMax * nAstroPSolved; ii < VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam + nGlobalParam; ii++) + { + if (preCondVect[ii] == 0.0) { - if(ii-VrIdAstroPDimMax*nAstroPSolved<nAttParam) - printf("ERROR Att ZERO column: PE=%d preCondVect[%ld]=0.0 AttParam=%ld \n",myid,ii, ii-VrIdAstroPDimMax*nAstroPSolved); - if(ii-VrIdAstroPDimMax*nAstroPSolved>nAttParam && ii-VrIdAstroPDimMax*nAstroPSolved<nAttParam+nInstrParam) - printf("ERROR Instr ZERO column: PE=%d preCondVect[%ld]=0.0 InstrParam=%ld \n",myid,ii, ii-(VrIdAstroPDimMax*nAstroPSolved+nAttParam)); - if(ii-VrIdAstroPDimMax*nAstroPSolved>nAttParam+nInstrParam) - printf("ERROR Global ZERO column: PE=%d preCondVect[%ld]=0.0 GlobalParam=%ld \n",myid,ii, ii-(VrIdAstroPDimMax*nAstroPSolved+nAttParam+nInstrParam)); - MPI_Abort(MPI_COMM_WORLD,1); + if (ii - VrIdAstroPDimMax * nAstroPSolved < nAttParam) + printf("ERROR Att ZERO column: PE=%d preCondVect[%ld]=0.0 AttParam=%ld \n", myid, ii, ii - VrIdAstroPDimMax * nAstroPSolved); + if (ii - VrIdAstroPDimMax * nAstroPSolved > nAttParam && ii - VrIdAstroPDimMax * nAstroPSolved < nAttParam + nInstrParam) + printf("ERROR Instr ZERO column: PE=%d preCondVect[%ld]=0.0 InstrParam=%ld \n", myid, ii, ii - (VrIdAstroPDimMax * nAstroPSolved + nAttParam)); + if (ii - VrIdAstroPDimMax * nAstroPSolved > nAttParam + nInstrParam) + printf("ERROR Global ZERO column: PE=%d preCondVect[%ld]=0.0 GlobalParam=%ld \n", myid, ii, ii - (VrIdAstroPDimMax * nAstroPSolved + nAttParam + nInstrParam)); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } preCondVect[ii] = 1.0; } - } - - if(myid==0) + + if (myid == 0) { printf("Computation of the preconditioning vector finished.\n"); } - comlsqr.nvinc=0; - comlsqr.parOss=(long) nparam; - comlsqr.nunk=nunk; - comlsqr.offsetAttParam=offsetAttParam; - comlsqr.offsetInstrParam=offsetInstrParam; - comlsqr.offsetGlobParam=offsetGlobParam; - comlsqr.nAttParam=nAttParam; - comlsqr.instrConst[0]=instrConst[0]; - comlsqr.instrConst[1]=instrConst[1]; - comlsqr.instrConst[2]=instrConst[2]; - comlsqr.instrConst[3]=instrConst[3]; - comlsqr.timeCPR=timeCPR; - comlsqr.timeLimit=timeLimit; - comlsqr.itnCPR=itnCPR; - comlsqr.itnCPRstop=itnCPRstop; - comlsqr.itnLimit=itnlim; - comlsqr.Test=0; //it is not a running test but a production run - - initThread(matrixIndex,&comlsqr); - - - endTime=MPI_Wtime()-endTime; + comlsqr.nvinc = 0; + comlsqr.parOss = (long)nparam; + comlsqr.nunk = nunk; + comlsqr.offsetAttParam = offsetAttParam; + comlsqr.offsetInstrParam = offsetInstrParam; + comlsqr.offsetGlobParam = offsetGlobParam; + comlsqr.nAttParam = nAttParam; + comlsqr.instrConst[0] = instrConst[0]; + comlsqr.instrConst[1] = instrConst[1]; + comlsqr.instrConst[2] = instrConst[2]; + comlsqr.instrConst[3] = instrConst[3]; + comlsqr.timeCPR = timeCPR; + comlsqr.timeLimit = timeLimit; + comlsqr.itnCPR = itnCPR; + comlsqr.itnCPRstop = itnCPRstop; + comlsqr.itnLimit = itnlim; + comlsqr.Test = 0; //it is not a running test but a production run + + initThread(matrixIndex, &comlsqr); + + endTime = MPI_Wtime() - endTime; MPI_Barrier(MPI_COMM_WORLD); - + //////// WRITE BIN FILES and FileConstr_GsrSolProps.dat - + //////////////////////////// noiter - if(noIter){ - if(myid==0) printf("\nEnd run: -noiter option givens.\n"); - + if (noIter) + { + if (myid == 0) + printf("\nEnd run: -noiter option givens.\n"); + MPI_Finalize(); exit(EXIT_SUCCESS); - + } /////////////// MAIN CALL - + ///////////// // This function computes the product of system matrix by precondVect. This avoids to compute the produsct in aprod for each iteration. - if(myid==0 && debugMode) + if (myid == 0 && debugMode) { - printf("TEST LSQR START nobs=%ld, nunk=%ld, damp=%f, knownTerms[0]=%f, knownTerms[%ld]=%f, atol=%f btol=%f conlim=%f itnlim=%ld systemMatrix[0]=%f, systemMatrix[%ld]=%f matrixIndex[0]=%ld matrixIndex[%ld]=%ld instrCol[0]=%d instrCol[%ld]=%d preCondVect[0]=%f preCondVect[%ld]=%f preCondVect[%ld]=%f nunkSplit=%ld\n",nobs, nunk, damp, knownTerms[0], mapNoss[myid]-1,knownTerms[mapNoss[myid]-1], atol, btol,conlim,itnlim, systemMatrix[0],mapNcoeff[myid]-1,systemMatrix[mapNcoeff[myid]-1], matrixIndex[0],mapNoss[myid]*2-1, matrixIndex[mapNoss[myid]*2-1], instrCol[0], mapNoss[myid]*nInstrPSolved -1,instrCol[mapNoss[myid]*nInstrPSolved -1], preCondVect[0],VrIdAstroPDim*nAstroPSolved-1, preCondVect[VrIdAstroPDim*nAstroPSolved-1], VrIdAstroPDim*nAstroPSolved, preCondVect[VrIdAstroPDim*nAstroPSolved], nunkSplit); + printf("TEST LSQR START nobs=%ld, nunk=%ld, damp=%f, knownTerms[0]=%f, knownTerms[%ld]=%f, atol=%f btol=%f conlim=%f itnlim=%ld systemMatrix[0]=%f, systemMatrix[%ld]=%f matrixIndex[0]=%ld matrixIndex[%ld]=%ld instrCol[0]=%d instrCol[%ld]=%d preCondVect[0]=%f preCondVect[%ld]=%f preCondVect[%ld]=%f nunkSplit=%ld\n", nobs, nunk, damp, knownTerms[0], mapNoss[myid] - 1, knownTerms[mapNoss[myid] - 1], atol, btol, conlim, itnlim, systemMatrix[0], mapNcoeff[myid] - 1, systemMatrix[mapNcoeff[myid] - 1], matrixIndex[0], mapNoss[myid] * 2 - 1, matrixIndex[mapNoss[myid] * 2 - 1], instrCol[0], mapNoss[myid] * nInstrPSolved - 1, instrCol[mapNoss[myid] * nInstrPSolved - 1], preCondVect[0], VrIdAstroPDim * nAstroPSolved - 1, preCondVect[VrIdAstroPDim * nAstroPSolved - 1], VrIdAstroPDim * nAstroPSolved, preCondVect[VrIdAstroPDim * nAstroPSolved], nunkSplit); } - precondSystemMatrix(systemMatrix, preCondVect, matrixIndex,instrCol,comlsqr); + precondSystemMatrix(systemMatrix, preCondVect, matrixIndex, instrCol, comlsqr); //systemMatrix is passed to lsqr already conditioned. - if(myid==0) { + if (myid == 0) + { printf("System built, ready to call LSQR.\nPlease wait. System solution is underway..."); } //////////////////// - startTime=MPI_Wtime(); + startTime = MPI_Wtime(); seconds[1] = time(NULL); tot_sec[0] = seconds[1] - seconds[0]; - comlsqr.totSec=tot_sec[0]; - if(myid==0) printf("Starting lsqr after sec: %ld\n", tot_sec[0]); + comlsqr.totSec = tot_sec[0]; + if (myid == 0) + printf("Starting lsqr after sec: %ld\n", tot_sec[0]); chdir(wpath); - if(outputDirOpt) chdir(outputDir); // go to output dir + if (outputDirOpt) + chdir(outputDir); // go to output dir + + lsqr(nobs, nunk, damp, knownTerms, vVect, wVect, xSolution, standardError, atol, btol, conlim, - (int) itnlim, &istop, &itn, &anorm, &acond, &rnorm, &arnorm, - &xnorm, systemMatrix, matrixIndex, instrCol, instrConstrIlung,preCondVect,comlsqr); - + (int)itnlim, &istop, &itn, &anorm, &acond, &rnorm, &arnorm, + &xnorm, systemMatrix, matrixIndex, instrCol, instrConstrIlung, preCondVect, comlsqr); + /////////////////////////// MPI_Barrier(MPI_COMM_WORLD); - endTime=MPI_Wtime(); - double clockTime=MPI_Wtime(); - if(myid==0) printf("Global Time for lsqr =%f sec \n",endTime-startTime); + endTime = MPI_Wtime(); + double clockTime = MPI_Wtime(); + if (myid == 0) + printf("Global Time for lsqr =%f sec \n", endTime - startTime); seconds[2] = time(NULL); tot_sec[1] = seconds[2] - seconds[1]; - - long thetaCol=0, muthetaCol=0; + + long thetaCol = 0, muthetaCol = 0; ldiv_t res_ldiv; - long flagTheta=0, flagMuTheta=0; - - if(nAstroPSolved==2) { - thetaCol=1; - muthetaCol=0; + long flagTheta = 0, flagMuTheta = 0; + + if (nAstroPSolved == 2) + { + thetaCol = 1; + muthetaCol = 0; } - else if(nAstroPSolved==3) { - thetaCol=2; - muthetaCol=0; + else if (nAstroPSolved == 3) + { + thetaCol = 2; + muthetaCol = 0; } - else if(nAstroPSolved==4) { - thetaCol=1; - muthetaCol=3; + else if (nAstroPSolved == 4) + { + thetaCol = 1; + muthetaCol = 3; } - else if(nAstroPSolved==5) { - thetaCol=2; - muthetaCol=4; + else if (nAstroPSolved == 5) + { + thetaCol = 2; + muthetaCol = 4; } - + double epsilon; - double localSumX=0, localSumXsq=0, sumX=0, sumXsq=0, average=0, rms=0; - double dev=0, localMaxDev=0, maxDev=0; - + double localSumX = 0, localSumXsq = 0, sumX = 0, sumXsq = 0, average = 0, rms = 0; + double dev = 0, localMaxDev = 0, maxDev = 0; + ///////// Each PE runs over the its Astrometric piece - if(muthetaCol==0) - for(ii=0; ii<VrIdAstroPDim*nAstroPSolved; ii++) { - res_ldiv=ldiv((ii-thetaCol),nAstroPSolved); - flagTheta=res_ldiv.rem; - if(flagTheta==0) - { - xSolution[ii]*=(-preCondVect[ii]); - if(idtest) + if (muthetaCol == 0) + for (ii = 0; ii < VrIdAstroPDim * nAstroPSolved; ii++) + { + res_ldiv = ldiv((ii - thetaCol), nAstroPSolved); + flagTheta = res_ldiv.rem; + if (flagTheta == 0) + { + xSolution[ii] *= (-preCondVect[ii]); + if (idtest) { - epsilon=xSolution[ii]+1.0; - localSumX-=epsilon; - dev=fabs(epsilon); - if(dev>localMaxDev) localMaxDev=dev; + epsilon = xSolution[ii] + 1.0; + localSumX -= epsilon; + dev = fabs(epsilon); + if (dev > localMaxDev) + localMaxDev = dev; } } else { - xSolution[ii]*=preCondVect[ii]; // the corrections in theta are converted for consistency with the naming conventions in the Data Model to corrections in delta by a change of sign (Mantis Issue 0013081) - if(idtest) + xSolution[ii] *= preCondVect[ii]; // the corrections in theta are converted for consistency with the naming conventions in the Data Model to corrections in delta by a change of sign (Mantis Issue 0013081) + if (idtest) { - epsilon=xSolution[ii]-1.0; - localSumX+=epsilon; - dev=fabs(epsilon); - if(dev>localMaxDev) localMaxDev=dev; + epsilon = xSolution[ii] - 1.0; + localSumX += epsilon; + dev = fabs(epsilon); + if (dev > localMaxDev) + localMaxDev = dev; } - } - if(idtest) localSumXsq+=epsilon*epsilon; - standardError[ii]*=preCondVect[ii]; + if (idtest) + localSumXsq += epsilon * epsilon; + standardError[ii] *= preCondVect[ii]; } else - for(ii=0; ii<VrIdAstroPDim*nAstroPSolved; ii++) { - res_ldiv=ldiv((ii-thetaCol),nAstroPSolved); - flagTheta=res_ldiv.rem; - res_ldiv=ldiv((ii-muthetaCol),nAstroPSolved); - flagMuTheta=res_ldiv.rem; - if((flagTheta==0) || (flagMuTheta==0)) { - xSolution[ii]*=(-preCondVect[ii]); - if(idtest) { - epsilon=xSolution[ii]+1.0; - localSumX-=epsilon; - dev=fabs(epsilon); - if(dev>localMaxDev) localMaxDev=dev; + for (ii = 0; ii < VrIdAstroPDim * nAstroPSolved; ii++) + { + res_ldiv = ldiv((ii - thetaCol), nAstroPSolved); + flagTheta = res_ldiv.rem; + res_ldiv = ldiv((ii - muthetaCol), nAstroPSolved); + flagMuTheta = res_ldiv.rem; + if ((flagTheta == 0) || (flagMuTheta == 0)) + { + xSolution[ii] *= (-preCondVect[ii]); + if (idtest) + { + epsilon = xSolution[ii] + 1.0; + localSumX -= epsilon; + dev = fabs(epsilon); + if (dev > localMaxDev) + localMaxDev = dev; } - } else { - xSolution[ii]*=preCondVect[ii]; // the corrections in theta are converted for consistency with the naming conventions in the Data Model to corrections in delta by a change of sign (Mantis Issue 0013081) - if(idtest) { - epsilon=xSolution[ii]-1.0; - localSumX+=epsilon; - dev=fabs(epsilon); - if(dev>localMaxDev) localMaxDev=dev; + } + else + { + xSolution[ii] *= preCondVect[ii]; // the corrections in theta are converted for consistency with the naming conventions in the Data Model to corrections in delta by a change of sign (Mantis Issue 0013081) + if (idtest) + { + epsilon = xSolution[ii] - 1.0; + localSumX += epsilon; + dev = fabs(epsilon); + if (dev > localMaxDev) + localMaxDev = dev; } } - if(idtest) localSumXsq+=epsilon*epsilon; - standardError[ii]*=preCondVect[ii]; + if (idtest) + localSumXsq += epsilon * epsilon; + standardError[ii] *= preCondVect[ii]; } //////////// End of de-preconditioning for the Astrometric unknowns - + //////////// Then only PE=0 runs over the shared unknowns (Attitude, Instrument, and Global) - if(myid==0) - for(ii=VroffsetAttParam; ii<nunkSplit; ii++) { - xSolution[ii]*=preCondVect[ii]; - if(idtest) { - localSumX+=(xSolution[ii]-1.0); - dev=fabs(1.0-xSolution[ii]); - if(dev>localMaxDev) localMaxDev=dev; - localSumXsq+=(xSolution[ii]-1.0)*(xSolution[ii]-1.0); + if (myid == 0) + for (ii = VroffsetAttParam; ii < nunkSplit; ii++) + { + xSolution[ii] *= preCondVect[ii]; + if (idtest) + { + localSumX += (xSolution[ii] - 1.0); + dev = fabs(1.0 - xSolution[ii]); + if (dev > localMaxDev) + localMaxDev = dev; + localSumXsq += (xSolution[ii] - 1.0) * (xSolution[ii] - 1.0); } - standardError[ii]*=preCondVect[ii]; + standardError[ii] *= preCondVect[ii]; } //////////// End of de-preconditioning for the shared unknowns - - + //////////////// TEST per verificare le somme di idtest.... da commentare/eliminare /* if(idtest) @@ -2854,39 +3230,72 @@ int main(int argc, char **argv) { } */ //////////////// Fine TEST - + + //print matrix + if(myid==0 ) + { + FILE * fp1; + // FILE * fp2; + + + fp1 = fopen ("./vVect.txt","w"); + // fp2 = fopen ("./matrixIndex.txt","w"); + + + for (ii = 0; ii < nunkSplit; ii++) + { + fprintf(fp1, "%16.12le \n", vVect[ii]); + // fprintf(fp2, "%16.12le \n", matrixIndex[ii]); + + + //fprintf("knownTerms[%ld]=%16.12le \n", ii,knownTerms[ii]); + } + fclose (fp1); + //fclose (fp2); + + } + + + free(systemMatrix); free(matrixIndex); free(instrCol); free(knownTerms); + + + + + + free(vVect); free(wVect); free(preCondVect); - if(idtest) + if (idtest) { - MPI_Reduce(&localSumX,&sumX,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD); - MPI_Reduce(&localSumXsq,&sumXsq,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD); - MPI_Reduce(&localMaxDev,&maxDev,1,MPI_DOUBLE,MPI_MAX,0,MPI_COMM_WORLD); + MPI_Reduce(&localSumX, &sumX, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + MPI_Reduce(&localSumXsq, &sumXsq, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + MPI_Reduce(&localMaxDev, &maxDev, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); } - - if(myid==0) + + if (myid == 0) { - if(idtest) + if (idtest) { - average=sumX/nunk; - rms=pow(sumXsq/nunk-pow(average,2.0),0.5); + average = sumX / nunk; + rms = pow(sumXsq / nunk - pow(average, 2.0), 0.5); printf("Average deviation from ID solution: %le.\n", average); printf(" rms: %le.\n", rms); printf("Maximum deviation from ID solution: %le.\n", maxDev); } } - - if(istop==1000 && wrsol==0) + + if (istop == 1000 && wrsol == 0) { - if(myid==0){ - printf("Reached limit at itn=%d. Execution stopped. CPR written!\n",itn); - ffcont=fopen("CPR_CONT","w"); + if (myid == 0) + { + printf("Reached limit at itn=%d. Execution stopped. CPR written!\n", itn); + ffcont = fopen("CPR_CONT", "w"); fclose(ffcont); } MPI_Finalize(); @@ -2894,283 +3303,304 @@ int main(int argc, char **argv) { } /////////////// ///////////// Initialize the output filename - if(istop==1000){ - sprintf(filenameAstroResults, "%s%d%s", "GsrAstroParamSolution_intermediate_",itn,".bin"); // file storing the Astrometric Parameters - sprintf(filenameAttResults, "%s%d%s","GsrAttitudeParamSolution_intermediate_",itn,".bin"); // file storing the Attitude Parameters - sprintf(filenameInstrResults, "%s%d%s","GsrInstrParamSolution_intermediate_",itn,".bin"); // file storing the Instrument Parameters - sprintf(filenameGlobalResults, "%s%d%s","GsrGlobalParamSolution_intermediate_",itn,".bin"); // file storing the Global Parameters - sprintf(filenameSolPropsFinal,"GsrFinal_intermediate_%d_%s",itn, argv[argc-1]); - } else{ - if(myid==0){ + if (istop == 1000) + { + sprintf(filenameAstroResults, "%s%d%s", "GsrAstroParamSolution_intermediate_", itn, ".bin"); // file storing the Astrometric Parameters + sprintf(filenameAttResults, "%s%d%s", "GsrAttitudeParamSolution_intermediate_", itn, ".bin"); // file storing the Attitude Parameters + sprintf(filenameInstrResults, "%s%d%s", "GsrInstrParamSolution_intermediate_", itn, ".bin"); // file storing the Instrument Parameters + sprintf(filenameGlobalResults, "%s%d%s", "GsrGlobalParamSolution_intermediate_", itn, ".bin"); // file storing the Global Parameters + sprintf(filenameSolPropsFinal, "GsrFinal_intermediate_%d_%s", itn, argv[argc - 1]); + } + else + { + if (myid == 0) + { printf("Execution finished END_FILE written!\n"); chdir(wpath); - ffcont=fopen("END_FILE","w"); + ffcont = fopen("END_FILE", "w"); fclose(ffcont); system("rm CPR_CONT"); - if(outputDirOpt) chdir(outputDir); // go to output dir - } - sprintf(filenameAstroResults, "%s", "GsrAstroParamSolution.bin"); // file storing the Astrometric Parameters - sprintf(filenameAttResults, "%s","GsrAttitudeParamSolution.bin"); // file storing the Attitude Parameters - sprintf(filenameInstrResults, "%s","GsrInstrParamSolution.bin"); // file storing the Instrument Parameters - sprintf(filenameGlobalResults, "%s","GsrGlobalParamSolution.bin"); // file storing the Global Parameters - sprintf(filenameSolPropsFinal,"GsrFinal_%s", argv[argc-1]); + if (outputDirOpt) + chdir(outputDir); // go to output dir + } + sprintf(filenameAstroResults, "%s", "GsrAstroParamSolution.bin"); // file storing the Astrometric Parameters + sprintf(filenameAttResults, "%s", "GsrAttitudeParamSolution.bin"); // file storing the Attitude Parameters + sprintf(filenameInstrResults, "%s", "GsrInstrParamSolution.bin"); // file storing the Instrument Parameters + sprintf(filenameGlobalResults, "%s", "GsrGlobalParamSolution.bin"); // file storing the Global Parameters + sprintf(filenameSolPropsFinal, "GsrFinal_%s", argv[argc - 1]); } - if(debugMode && myid==0) printf("Output %s %s %s %s %s\n",filenameSolProps,filenameAstroResults, filenameAttResults, filenameInstrResults, filenameGlobalResults); + if (debugMode && myid == 0) + printf("Output %s %s %s %s %s\n", filenameSolProps, filenameAstroResults, filenameAttResults, filenameInstrResults, filenameGlobalResults); ///////////////////////////////////////////// - + MPI_Status statusMpi; if (myid == 0) { printf("Processing finished.\n"); fflush(stdout); - for (ii = 0; ii < 10; ii++) printf("xSolution[%ld]=%16.12le \t standardError[%ld]=%16.12le\n", ii, xSolution[ii],ii,standardError[ii]); + for (ii = 0; ii < 10; ii++) + printf("xSolution[%ld]=%16.12le \t standardError[%ld]=%16.12le \n", ii, xSolution[ii], ii, standardError[ii]); } - + ////////// Writing final solution - - if(myid==0) + + if (myid == 0) { - + ////////// Writing the raw results to the files GsrFinal_GsrSolProps.dat - - - fpSolPropsFinal=fopen(filenameSolPropsFinal,"w"); + + fpSolPropsFinal = fopen(filenameSolPropsFinal, "w"); if (!fpSolPropsFinal) { - printf("Error while open %s\n",filenameSolPropsFinal); - MPI_Abort(MPI_COMM_WORLD,1); + printf("Error while open %s\n", filenameSolPropsFinal); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - fprintf(fpSolPropsFinal, "sphereId= %ld\n",sphereId) ; - fprintf(fpSolPropsFinal, "nStar= %ld\n",nStar) ; - fprintf(fpSolPropsFinal, "nAttParam= %d\n",nAttParam) ; - fprintf(fpSolPropsFinal, "nInstrParam= %d\n",nInstrParam) ; - fprintf(fpSolPropsFinal, "nInstrParamTot= %d\n",nInstrParamTot) ; - fprintf(fpSolPropsFinal, "nGlobalParam= %d\n",nGlobalParam) ; - fprintf(fpSolPropsFinal, "nAstroPSolved= %d\n",nAstroPSolved) ; - fprintf(fpSolPropsFinal, "nInstrPSolved= %d\n",nInstrPSolved) ; - fprintf(fpSolPropsFinal, "nFoVs= %d\n",nFoVs); - fprintf(fpSolPropsFinal, "nCCDs= %d\n",nCCDs); - fprintf(fpSolPropsFinal, "nPixelColumns= %d\n",nPixelColumns); - fprintf(fpSolPropsFinal, "nTimeIntervals= %d\n",nTimeIntervals); - fprintf(fpSolPropsFinal, "lSQRacond= %lf\n",acond) ; - fprintf(fpSolPropsFinal, "lSQRanorm= %lf\n",anorm) ; - fprintf(fpSolPropsFinal, "lSQRarnorm= %lf\n",arnorm) ; - fprintf(fpSolPropsFinal, "lSQRitNumb= %d\n",itn) ; - fprintf(fpSolPropsFinal, "lSQRrnorm= %lf\n",rnorm) ; - fprintf(fpSolPropsFinal, "lSQRstopCond= %d\n",istop) ; - fprintf(fpSolPropsFinal, "lSQRxnorm= %lf\n",xnorm) ; + fprintf(fpSolPropsFinal, "sphereId= %ld\n", sphereId); + fprintf(fpSolPropsFinal, "nStar= %ld\n", nStar); + fprintf(fpSolPropsFinal, "nAttParam= %d\n", nAttParam); + fprintf(fpSolPropsFinal, "nInstrParam= %d\n", nInstrParam); + fprintf(fpSolPropsFinal, "nInstrParamTot= %d\n", nInstrParamTot); + fprintf(fpSolPropsFinal, "nGlobalParam= %d\n", nGlobalParam); + fprintf(fpSolPropsFinal, "nAstroPSolved= %d\n", nAstroPSolved); + fprintf(fpSolPropsFinal, "nInstrPSolved= %d\n", nInstrPSolved); + fprintf(fpSolPropsFinal, "nFoVs= %d\n", nFoVs); + fprintf(fpSolPropsFinal, "nCCDs= %d\n", nCCDs); + fprintf(fpSolPropsFinal, "nPixelColumns= %d\n", nPixelColumns); + fprintf(fpSolPropsFinal, "nTimeIntervals= %d\n", nTimeIntervals); + fprintf(fpSolPropsFinal, "lSQRacond= %lf\n", acond); + fprintf(fpSolPropsFinal, "lSQRanorm= %lf\n", anorm); + fprintf(fpSolPropsFinal, "lSQRarnorm= %lf\n", arnorm); + fprintf(fpSolPropsFinal, "lSQRitNumb= %d\n", itn); + fprintf(fpSolPropsFinal, "lSQRrnorm= %lf\n", rnorm); + fprintf(fpSolPropsFinal, "lSQRstopCond= %d\n", istop); + fprintf(fpSolPropsFinal, "lSQRxnorm= %lf\n", xnorm); fclose(fpSolPropsFinal); - + ////////////////////// Writing GsrAstroParamSolution.bin - if(nAstroPSolved) + if (nAstroPSolved) { - long testOnStars=0; - fpAstroR=fopen(filenameAstroResults,"wb"); + long testOnStars = 0; + fpAstroR = fopen(filenameAstroResults, "wb"); if (!fpAstroR) { - printf("Error while open %s\n",filenameAstroResults); - MPI_Abort(MPI_COMM_WORLD,1); + printf("Error while open %s\n", filenameAstroResults); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - fwrite(&sphereId,sizeof(long),1,fpAstroR); - xAstro = (double *) calloc(VrIdAstroPDimMax*nAstroP, sizeof(double)); + fwrite(&sphereId, sizeof(long), 1, fpAstroR); + xAstro = (double *)calloc(VrIdAstroPDimMax * nAstroP, sizeof(double)); if (!xAstro) { printf("Error allocating xAstro\n"); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - for(ii=0; ii<VrIdAstroPDim; ii++) + for (ii = 0; ii < VrIdAstroPDim; ii++) { - for(jj=0; jj< nAstroPSolved;jj++) + for (jj = 0; jj < nAstroPSolved; jj++) { - xAstro[ii*nAstroP+mapAstroP[jj]] = xSolution[ii*nAstroPSolved+jj]; + xAstro[ii * nAstroP + mapAstroP[jj]] = xSolution[ii * nAstroPSolved + jj]; } } - fwrite(xAstro,sizeof(double),VrIdAstroPDim*nAstroP,fpAstroR); - testOnStars+=VrIdAstroPDim; - for(kk=1;kk<nproc;kk++) + fwrite(xAstro, sizeof(double), VrIdAstroPDim * nAstroP, fpAstroR); + testOnStars += VrIdAstroPDim; + for (kk = 1; kk < nproc; kk++) { - offset=0; + offset = 0; MPI_Recv(&VrIdAstroPDimRecv, 1, MPI_LONG, kk, 10, MPI_COMM_WORLD, &statusMpi); - mpi_recv(xSolution, VrIdAstroPDimRecv*nAstroPSolved, MPI_DOUBLE, kk, 11,MPI_COMM_WORLD, &statusMpi); - if(comlsqr.mapStar[kk][0]==comlsqr.mapStar[kk-1][1]) offset=1; - for(ii=0+offset; ii<VrIdAstroPDimRecv; ii++) + mpi_recv(xSolution, VrIdAstroPDimRecv * nAstroPSolved, MPI_DOUBLE, kk, 11, MPI_COMM_WORLD, &statusMpi); + if (comlsqr.mapStar[kk][0] == comlsqr.mapStar[kk - 1][1]) + offset = 1; + for (ii = 0 + offset; ii < VrIdAstroPDimRecv; ii++) { - for(jj=0; jj< nAstroPSolved;jj++) + for (jj = 0; jj < nAstroPSolved; jj++) { - xAstro[(ii-offset)*nAstroP+mapAstroP[jj]] = xSolution[ii*nAstroPSolved+jj]; + xAstro[(ii - offset) * nAstroP + mapAstroP[jj]] = xSolution[ii * nAstroPSolved + jj]; } } - fwrite(xAstro,sizeof(double),(VrIdAstroPDimRecv-offset)*nAstroP,fpAstroR); - testOnStars+=VrIdAstroPDimRecv-offset; + fwrite(xAstro, sizeof(double), (VrIdAstroPDimRecv - offset) * nAstroP, fpAstroR); + testOnStars += VrIdAstroPDimRecv - offset; } free(xAstro); - - if(testOnStars!=nStar) + + if (testOnStars != nStar) { - printf("Error on xAstro testOnStar =%ld not equal to nmStar=%ld\n",testOnStars,nStar); - MPI_Abort(MPI_COMM_WORLD,1); + printf("Error on xAstro testOnStar =%ld not equal to nmStar=%ld\n", testOnStars, nStar); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - testOnStars=0; - standardErrorAstro = (double *) calloc(VrIdAstroPDimMax*nAstroP, sizeof(double)); + testOnStars = 0; + standardErrorAstro = (double *)calloc(VrIdAstroPDimMax * nAstroP, sizeof(double)); if (!standardErrorAstro) { printf("Error allocating standardErrorAstro\n"); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - for(ii=0; ii<VrIdAstroPDim; ii++) + for (ii = 0; ii < VrIdAstroPDim; ii++) { - for(jj=0; jj< nAstroPSolved;jj++) + for (jj = 0; jj < nAstroPSolved; jj++) { - standardErrorAstro[ii*nAstroP+mapAstroP[jj]] =standardError[ii*nAstroPSolved+jj]; + standardErrorAstro[ii * nAstroP + mapAstroP[jj]] = standardError[ii * nAstroPSolved + jj]; } } - fwrite(standardErrorAstro,sizeof(double),VrIdAstroPDim*nAstroP,fpAstroR); - testOnStars+=VrIdAstroPDim; - for(kk=1;kk<nproc;kk++) + fwrite(standardErrorAstro, sizeof(double), VrIdAstroPDim * nAstroP, fpAstroR); + testOnStars += VrIdAstroPDim; + for (kk = 1; kk < nproc; kk++) { - offset=0; + offset = 0; MPI_Recv(&VrIdAstroPDimRecv, 1, MPI_LONG, kk, 12, MPI_COMM_WORLD, &statusMpi); - MPI_Recv(standardError, VrIdAstroPDimRecv*nAstroPSolved , MPI_DOUBLE, kk, 13,MPI_COMM_WORLD, &statusMpi); - if(comlsqr.mapStar[kk][0]==comlsqr.mapStar[kk-1][1]) offset=1; - for(ii=0+offset; ii<VrIdAstroPDimRecv; ii++) + MPI_Recv(standardError, VrIdAstroPDimRecv * nAstroPSolved, MPI_DOUBLE, kk, 13, MPI_COMM_WORLD, &statusMpi); + if (comlsqr.mapStar[kk][0] == comlsqr.mapStar[kk - 1][1]) + offset = 1; + for (ii = 0 + offset; ii < VrIdAstroPDimRecv; ii++) { - for(jj=0; jj< nAstroPSolved;jj++) + for (jj = 0; jj < nAstroPSolved; jj++) { - standardErrorAstro[(ii-offset)*nAstroP+mapAstroP[jj]] = standardError[ii*nAstroPSolved+jj]; + standardErrorAstro[(ii - offset) * nAstroP + mapAstroP[jj]] = standardError[ii * nAstroPSolved + jj]; } } - fwrite(standardErrorAstro,sizeof(double),(VrIdAstroPDimRecv-offset)*nAstroP,fpAstroR); - testOnStars+=VrIdAstroPDimRecv-offset; + fwrite(standardErrorAstro, sizeof(double), (VrIdAstroPDimRecv - offset) * nAstroP, fpAstroR); + testOnStars += VrIdAstroPDimRecv - offset; } free(standardErrorAstro); - if(testOnStars!=nStar) + if (testOnStars != nStar) { - printf("Error on standardErrorAstro testOnStar =%ld not equal to nmStar=%ld\n",testOnStars,nStar); - MPI_Abort(MPI_COMM_WORLD,1); + printf("Error on standardErrorAstro testOnStar =%ld not equal to nmStar=%ld\n", testOnStars, nStar); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } fclose(fpAstroR); ////////////////////////////////////////////////////////// } ////////////////////// writing GsrAttitudeParamSolution.bin - fpAttR=fopen(filenameAttResults,"wb"); + fpAttR = fopen(filenameAttResults, "wb"); if (!fpAttR) { - printf("Error while open %s\n",filenameAttResults); - MPI_Abort(MPI_COMM_WORLD,1); + printf("Error while open %s\n", filenameAttResults); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - fwrite(&sphereId,sizeof(long),1,fpAttR); - fwrite(&xSolution[VroffsetAttParam],sizeof(double),nAttParam,fpAttR); - fwrite(&standardError[VroffsetAttParam],sizeof(double),nAttParam,fpAttR); + fwrite(&sphereId, sizeof(long), 1, fpAttR); + fwrite(&xSolution[VroffsetAttParam], sizeof(double), nAttParam, fpAttR); + fwrite(&standardError[VroffsetAttParam], sizeof(double), nAttParam, fpAttR); fclose(fpAttR); ////////////////////////////////////////////////////////// - + ////////////////////// writing GsrInstrParamSolution.bin - fpInstrR=fopen(filenameInstrResults,"wb"); + fpInstrR = fopen(filenameInstrResults, "wb"); if (!fpInstrR) { - printf("Error while open %s\n",filenameInstrResults); - MPI_Abort(MPI_COMM_WORLD,1); + printf("Error while open %s\n", filenameInstrResults); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - double *xInstr,*seInstr; - xInstr=(double *) calloc(nInstrParamTot, sizeof(double)); - seInstr=(double *) calloc(nInstrParamTot, sizeof(double)); - if(nInstrPSolved!=nInstrP) + double *xInstr, *seInstr; + xInstr = (double *)calloc(nInstrParamTot, sizeof(double)); + seInstr = (double *)calloc(nInstrParamTot, sizeof(double)); + if (nInstrPSolved != nInstrP) { int fixedOffsetCMag = nCCDs; - int fixedOffsetCnu = fixedOffsetCMag+nFoVs*nCCDs; - int fixedOffsetCdelta_eta = fixedOffsetCnu+nCCDs*nPixelColumns; - int fixedOffsetCDelta_eta = fixedOffsetCdelta_eta+3*nFoVs*nCCDs*nTimeIntervals; - int fixedOffsetCdelta_zeta = fixedOffsetCDelta_eta+nCCDs*nPixelColumns; - - int counterInstr=0; - if(maInstrFlag){ - for(int k=0;k<fixedOffsetCMag;k++){ - xInstr[k]=xSolution[VroffsetAttParam+nAttParam+counterInstr]; - seInstr[k]=standardError[VroffsetAttParam+nAttParam+counterInstr]; + int fixedOffsetCnu = fixedOffsetCMag + nFoVs * nCCDs; + int fixedOffsetCdelta_eta = fixedOffsetCnu + nCCDs * nPixelColumns; + int fixedOffsetCDelta_eta = fixedOffsetCdelta_eta + 3 * nFoVs * nCCDs * nTimeIntervals; + int fixedOffsetCdelta_zeta = fixedOffsetCDelta_eta + nCCDs * nPixelColumns; + + int counterInstr = 0; + if (maInstrFlag) + { + for (int k = 0; k < fixedOffsetCMag; k++) + { + xInstr[k] = xSolution[VroffsetAttParam + nAttParam + counterInstr]; + seInstr[k] = standardError[VroffsetAttParam + nAttParam + counterInstr]; counterInstr++; } } - if(nuInstrFlag){ - for(int k=fixedOffsetCMag;k<fixedOffsetCnu;k++){ - xInstr[k]=xSolution[VroffsetAttParam+nAttParam+counterInstr]; - seInstr[k]=standardError[VroffsetAttParam+nAttParam+counterInstr]; + if (nuInstrFlag) + { + for (int k = fixedOffsetCMag; k < fixedOffsetCnu; k++) + { + xInstr[k] = xSolution[VroffsetAttParam + nAttParam + counterInstr]; + seInstr[k] = standardError[VroffsetAttParam + nAttParam + counterInstr]; counterInstr++; } } - if(ssInstrFlag){ - for(int k=fixedOffsetCnu;k<fixedOffsetCdelta_eta;k++){ - xInstr[k]=xSolution[VroffsetAttParam+nAttParam+counterInstr]; - seInstr[k]=standardError[VroffsetAttParam+nAttParam+counterInstr]; + if (ssInstrFlag) + { + for (int k = fixedOffsetCnu; k < fixedOffsetCdelta_eta; k++) + { + xInstr[k] = xSolution[VroffsetAttParam + nAttParam + counterInstr]; + seInstr[k] = standardError[VroffsetAttParam + nAttParam + counterInstr]; counterInstr++; } } - if(lsInstrFlag){ - for(int k=fixedOffsetCdelta_eta;k<fixedOffsetCDelta_eta;k++){ - xInstr[k]=xSolution[VroffsetAttParam+nAttParam+counterInstr]; - seInstr[k]=standardError[VroffsetAttParam+nAttParam+counterInstr]; + if (lsInstrFlag) + { + for (int k = fixedOffsetCdelta_eta; k < fixedOffsetCDelta_eta; k++) + { + xInstr[k] = xSolution[VroffsetAttParam + nAttParam + counterInstr]; + seInstr[k] = standardError[VroffsetAttParam + nAttParam + counterInstr]; counterInstr++; } } - if(ssInstrFlag){ - for(int k=fixedOffsetCDelta_eta;k<fixedOffsetCdelta_zeta;k++){ - xInstr[k]=xSolution[VroffsetAttParam+nAttParam+counterInstr]; - seInstr[k]=standardError[VroffsetAttParam+nAttParam+counterInstr]; + if (ssInstrFlag) + { + for (int k = fixedOffsetCDelta_eta; k < fixedOffsetCdelta_zeta; k++) + { + xInstr[k] = xSolution[VroffsetAttParam + nAttParam + counterInstr]; + seInstr[k] = standardError[VroffsetAttParam + nAttParam + counterInstr]; counterInstr++; } } - if(lsInstrFlag){ - for(int k=fixedOffsetCdelta_zeta;k<nInstrParamTot;k++){ - xInstr[k]=xSolution[VroffsetAttParam+nAttParam+counterInstr]; - seInstr[k]=standardError[VroffsetAttParam+nAttParam+counterInstr]; + if (lsInstrFlag) + { + for (int k = fixedOffsetCdelta_zeta; k < nInstrParamTot; k++) + { + xInstr[k] = xSolution[VroffsetAttParam + nAttParam + counterInstr]; + seInstr[k] = standardError[VroffsetAttParam + nAttParam + counterInstr]; counterInstr++; } } - if(counterInstr!=nInstrParam) { + if (counterInstr != nInstrParam) + { printf("SEVERE ERROR: counterInstr=%ld does not match nInstrParam=%ld while filling in xInstr and seInstr.\n", counterInstr, nInstrParam); - MPI_Abort(MPI_COMM_WORLD,1); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } } - fwrite(&sphereId,sizeof(long),1,fpInstrR); - fwrite(xInstr,sizeof(double),nInstrParamTot,fpInstrR); - fwrite(seInstr,sizeof(double),nInstrParamTot,fpInstrR); + fwrite(&sphereId, sizeof(long), 1, fpInstrR); + fwrite(xInstr, sizeof(double), nInstrParamTot, fpInstrR); + fwrite(seInstr, sizeof(double), nInstrParamTot, fpInstrR); fclose(fpInstrR); free(xInstr); free(seInstr); ////////////////////////////////////////////////////////// - + ////////////////////// writing GsrGlobalParamSolution.bin - fpGlobR=fopen(filenameGlobalResults,"wb"); + fpGlobR = fopen(filenameGlobalResults, "wb"); if (!fpGlobR) { - printf("Error while open %s\n",filenameGlobalResults); - MPI_Abort(MPI_COMM_WORLD,1); + printf("Error while open %s\n", filenameGlobalResults); + MPI_Abort(MPI_COMM_WORLD, 1); exit(EXIT_FAILURE); } - fwrite(&sphereId,sizeof(long),1,fpGlobR); - fwrite(&xSolution[VroffsetAttParam+nAttParam+nInstrParam],sizeof(double),nGlobalParam,fpGlobR); - fwrite(&standardError[VroffsetAttParam+nAttParam+nInstrParam],sizeof(double),nGlobalParam,fpGlobR); + fwrite(&sphereId, sizeof(long), 1, fpGlobR); + fwrite(&xSolution[VroffsetAttParam + nAttParam + nInstrParam], sizeof(double), nGlobalParam, fpGlobR); + fwrite(&standardError[VroffsetAttParam + nAttParam + nInstrParam], sizeof(double), nGlobalParam, fpGlobR); fclose(fpGlobR); ////////////////////////////////////////////////////////// - + } //if (myid==0) else { //////////////// send for AstroResults.bin - if(nAstroPSolved) + if (nAstroPSolved) { MPI_Send(&VrIdAstroPDim, 1, MPI_LONG, 0, 10, MPI_COMM_WORLD); - mpi_send(xSolution, VrIdAstroPDim*nAstroPSolved, MPI_DOUBLE, 0, 11,MPI_COMM_WORLD); + mpi_send(xSolution, VrIdAstroPDim * nAstroPSolved, MPI_DOUBLE, 0, 11, MPI_COMM_WORLD); MPI_Send(&VrIdAstroPDim, 1, MPI_LONG, 0, 12, MPI_COMM_WORLD); - MPI_Send(standardError, VrIdAstroPDim*nAstroPSolved , MPI_DOUBLE, 0, 13,MPI_COMM_WORLD); + MPI_Send(standardError, VrIdAstroPDim * nAstroPSolved, MPI_DOUBLE, 0, 13, MPI_COMM_WORLD); } ////////////////////////////////////////////////////////// } @@ -3178,17 +3608,20 @@ int main(int argc, char **argv) { // tolti i free() mancanti free(xSolution); free(standardError); - - if(myid==0) printf("\nEnd run.\n"); + + if (myid == 0) + printf("\nEnd run.\n"); seconds[3] = time(NULL); tot_sec[2] = seconds[3] - seconds[2]; tot_sec[3] = seconds[3] - seconds[0]; - - if(myid==0) printf("time before lsqr in sec: %ld\ntime for lsqr: %ld\n", tot_sec[0], - tot_sec[1]); - if(myid==0) printf("time after lsqr in sec: %ld\ntime TOTAL: %ld\n", tot_sec[2], - tot_sec[3]); - + + if (myid == 0) + printf("time before lsqr in sec: %ld\ntime for lsqr: %ld\n", tot_sec[0], + tot_sec[1]); + if (myid == 0) + printf("time after lsqr in sec: %ld\ntime TOTAL: %ld\n", tot_sec[2], + tot_sec[3]); + MPI_Finalize(); exit(EXIT_SUCCESS); } diff --git a/testMatrix.c b/testMatrix.c new file mode 100644 index 0000000..c7d96f8 --- /dev/null +++ b/testMatrix.c @@ -0,0 +1,63 @@ +#include <iostream> +#include <fstream> +#include <string> +#include <iomanip> + +using namespace std; + +int main(int argc, char *argv[]) +{ + ifstream myfile(argv[1]); + ifstream myfile1(argv[2]); + ofstream outfile("res.txt"); + + if (myfile.is_open() && myfile1.is_open()) + { + int arrSize = 0; + double arr[1001805]; // Ideally this would be a vector, but you said array + double arr1[1001805]; // Ideally this would be a vector, but you said array + + double res[1001805]; // Ideally this would be a vector, but you said array + + + while ( true) + { + double x; + myfile >> x; + if (myfile.eof()) + break; + arr[arrSize++] = x; + } + + arrSize=0; + while (true) + { + double x; + myfile1 >> x; + if (myfile1.eof()) + break; + arr1[arrSize] = x; + + res[arrSize]=arr[arrSize]-arr1[arrSize]; + outfile<<arrSize<<" "<<fixed<<setprecision(20)<< res[arrSize]<<" "<<arr[arrSize]<<" "<<arr1[arrSize]<<"\n"; + arrSize++; + } + + + + // I should have closed the file here, but as the program was ending I was lazy } + } + else + { + cout << "Unable to open file"; + } + + + outfile.close(); + myfile.close(); + myfile1.close(); + + return 0; + +} + diff --git a/util.c b/util.c old mode 100755 new mode 100644 index 8ad01c2..f64d64e --- a/util.c +++ b/util.c @@ -637,38 +637,42 @@ void initThread(long int *matrixIndex,struct comData *comlsqr) { int myid=comlsqr->myid; +/* comlsqr->nthreads=1; #ifdef OMP comlsqr->nthreads = omp_get_max_threads(); #endif +*/ int nthreads=comlsqr->nthreads; +int ntasks=comlsqr->ntasks; + /// Prepare the structure for the division of the for cycle in aprod mode=2 -comlsqr->mapForThread=(long **) calloc(nthreads,sizeof(long *)); -for(int n=0;n<nthreads;n++) +comlsqr->mapForThread=(long **) calloc(ntasks,sizeof(long *)); +for(int n=0;n<ntasks;n++) comlsqr->mapForThread[n]=(long *) calloc(3,sizeof(long)); -int nElements=comlsqr->mapNoss[myid]/nthreads; +int nElements=comlsqr->mapNoss[myid]/ntasks; comlsqr->mapForThread[0][0]=0; comlsqr->mapForThread[0][1]=nElements/2; comlsqr->mapForThread[0][2]=nElements; -if(comlsqr->mapNoss[myid]%nthreads>0) comlsqr->mapForThread[0][2]++; +if(comlsqr->mapNoss[myid]%ntasks>0) comlsqr->mapForThread[0][2]++; -for(int n=1;n<nthreads;n++) +for(int n=1;n<ntasks;n++) { comlsqr->mapForThread[n][0]=comlsqr->mapForThread[n-1][2]; comlsqr->mapForThread[n][1]=comlsqr->mapForThread[n][0]+nElements/2; comlsqr->mapForThread[n][2]=comlsqr->mapForThread[n][0]+nElements; - if(comlsqr->mapNoss[myid]%nthreads>n) comlsqr->mapForThread[n][2]++; + if(comlsqr->mapNoss[myid]%ntasks>n) comlsqr->mapForThread[n][2]++; } -comlsqr->mapForThread[nthreads-1][2]=comlsqr->mapNoss[myid]; +comlsqr->mapForThread[ntasks-1][2]=comlsqr->mapNoss[myid]; ////////////////////////////////// // Check for the NOT super-imposed stars at half cycle if(comlsqr->nAstroPSolved>0){ int smpFailed=0; - for(int n=1;n<nthreads;n++) + for(int n=1;n<ntasks;n++) { while(matrixIndex[2*(comlsqr->mapForThread[n-1][2]-1)]==matrixIndex[2*comlsqr->mapForThread[n][0]]) @@ -690,7 +694,7 @@ if(comlsqr->nAstroPSolved>0){ printf("UTIL: SEVERE WARNING PE=%d smpFailed\n",myid); comlsqr->mapForThread[0][0]=0; comlsqr->mapForThread[0][1]=comlsqr->mapNoss[myid]; comlsqr->mapForThread[0][2]=comlsqr->mapForThread[0][1]; - for(int n=1;n<nthreads;n++) + for(int n=1;n<ntasks;n++) { comlsqr->mapForThread[n][0]=comlsqr->mapNoss[myid]; comlsqr->mapForThread[n][1]=comlsqr->mapNoss[myid]; @@ -700,24 +704,28 @@ if(comlsqr->nAstroPSolved>0){ } ///// -if(comlsqr->myid==0) printf("\n\nRunning with OMP: nthreads=%d\n\n",nthreads); +if(comlsqr->myid==0) printf("\n\nRunning with OmpSs: ntasks=%d\n\n",ntasks); } +//not used void blocksAttIndep(long int *matrixIndex,struct comData *comlsqr) { //ATTENZIONE NON E? CORRETTA E NON VA MAI USATA SE nAstroPSolved=0 int myid=comlsqr->myid; - +/* comlsqr->nthreads=1; #ifdef OMP comlsqr->nthreads = omp_get_num_threads(); #endif +*/ int nthreads=comlsqr->nthreads; +int ntasks=comlsqr->ntasks; + comlsqr->nSubsetAtt=1; comlsqr->NOnSubsetAtt=1; -if(nthreads==1) +if(ntasks==1) return; int dependancyFound; @@ -729,8 +737,8 @@ dependancyFound=0; for(int i=0;i<comlsqr->nSubsetAtt;i++) //ciclo su tutti i sotto intervall { long totalEleInBlock=comlsqr->mapNoss[myid]/comlsqr->nSubsetAtt; //numero di elementi totali inclusi in tutte le thread nel blocco TBV - long totalEleInBlockThread= (comlsqr->mapNoss[myid]/comlsqr->nSubsetAtt)/nthreads; //elementi nella singola thread TBV - for(int nsubBlock=0;nsubBlock<nthreads;nsubBlock++) //nel sottointervallo cerco l'indipendenza degli indici nelle nthreads del sistema a partire dal blocco della prima tread che confronto con le successive e poi la seconda thread che confronto con la terza e seguenti ecc. ecc. + long totalEleInBlockThread= (comlsqr->mapNoss[myid]/comlsqr->nSubsetAtt)/ntasks; //elementi nella singola thread TBV + for(int nsubBlock=0;nsubBlock<ntasks;nsubBlock++) //nel sottointervallo cerco l'indipendenza degli indici nelle nthreads del sistema a partire dal blocco della prima tread che confronto con le successive e poi la seconda thread che confronto con la terza e seguenti ecc. ecc. { for(long j=totalEleInBlockThread*i;j<totalEleInBlockThread*(i+1)+1;j++) //j spazzola tutti gli elementi nel blocco della thread "nsubBlok" per poi confrontarlo con tutti gli elelementi delle thread seguenti { @@ -1568,6 +1576,8 @@ struct nullSpace cknullSpace(double * systemMatrix,long * matrixIndex,double *at long int nDegFreedomAtt,localAstroMax,offsetAttParam; long int *mapNoss, *mapNcoeff; time_t seconds[2], tot_sec; + int ntasks; + int nthreads; int **mapStar; @@ -1605,6 +1615,10 @@ struct nullSpace cknullSpace(double * systemMatrix,long * matrixIndex,double *at int nInstrParam=comlsqr.nInstrParam; int nGlobalParam=comlsqr.nGlobalParam; + ntasks=comlsqr.ntasks; + nthreads=comlsqr.nthreads; + + // errore ==> nparam=nAstroPSolved+comlsqr.nAttP+comlsqr.nInstrP+comlsqr.nGlobP; nparam=nAstroPSolved+comlsqr.nAttP+comlsqr.nInstrPSolved+comlsqr.nGlobP; nLocalStar=comlsqr.mapStar[myid][1]-comlsqr.mapStar[myid][0]+1; @@ -1792,6 +1806,7 @@ struct nullSpace cknullSpace(double * systemMatrix,long * matrixIndex,double *at */ }//pragma double normLoc; + //FV_ aggiungere ntasks a cblas_dnrm2 normLoc=cblas_dnrm2(mapNoss[myid],productNS,1); double normLoc2=normLoc*normLoc; double nrmGlob; @@ -2123,3 +2138,303 @@ float simfullram(long &nStar, long &nobs, float memGlobal, int nparam, int nAttP return prevmemGB; } +double aprodM1Obs(long ix,struct comData comlsqr, double *vVect, double *systemMatrix, long int *matrixIndex, int *instrCol){ + + int myid = comlsqr.myid; + short nAstroPSolved = comlsqr.nAstroPSolved; + long localAstroMax = comlsqr.VrIdAstroPDimMax * nAstroPSolved; + long nDegFreedomAtt = comlsqr.nDegFreedomAtt; + short nAttParAxis = comlsqr.nAttParAxis; + short nAttP = comlsqr.nAttP; + short nGlobP = comlsqr.nGlobP; + short nInstrPSolved = comlsqr.nInstrPSolved; + long offsetAttParam = comlsqr.offsetAttParam; + long offsetInstrParam = comlsqr.offsetInstrParam; + long offsetGlobParam = comlsqr.offsetGlobParam; + long lset=0; + long nparam = comlsqr.parOss; + short nAttAxes = comlsqr.nAttAxes; + int multMI = comlsqr.multMI; + long miValAstro = 0; + long miValAtt = 0; + long jstartAtt = 0; + long offLocalAstro = 0; + long offLocalAtt = 0; + long offLocalInstr = 0; //Offset on Instruments + long jstartAstro = 0; + long ixInstr = 0; + int nInstrVal = 0; + double sum=0.; + offLocalInstr = offsetInstrParam + (localAstroMax - offsetAttParam); //Offset on Instruments + nInstrVal = nAstroPSolved + nAttP; + offLocalAstro = comlsqr.mapStar[myid][0] * nAstroPSolved; //Offset on my mstars + offLocalAtt = localAstroMax - offsetAttParam; //Offset on attitude + long offLocalGlob = offsetGlobParam + (localAstroMax - offsetAttParam); //Offset on GlobP + int nGlobVal = nAstroPSolved + nAttP + nInstrPSolved; + jstartAstro = miValAstro - offLocalAstro; + + ///////////////////////////////////////////////////// + /// Mode 1 Astrometric Sect + if (nAstroPSolved) + { + + lset = ix * nparam; + if (matrixIndex[multMI * ix] != miValAstro) + { + miValAstro = matrixIndex[multMI * ix]; + jstartAstro = miValAstro - offLocalAstro; + } + for (long jx = jstartAstro; jx < jstartAstro + nAstroPSolved; jx++) + { + sum = sum + systemMatrix[lset] * vVect[jx]; + lset++; + } + } + ////////////////////////////////////////////////////// + /// Mode 1 Attitude Sect + if (nAttP) + { + lset = ix * nparam + nAstroPSolved; + miValAtt = matrixIndex[multMI * ix + (multMI - 1)]; + for (int nax = 0; nax < nAttAxes; nax++) + { + jstartAtt = miValAtt + offLocalAtt + nax * nDegFreedomAtt; + for (long inpax = jstartAtt; inpax < jstartAtt + nAttParAxis; inpax++) + { + sum = sum + systemMatrix[lset] * vVect[inpax]; + lset++; + } + } + } + ////////////////////////////////////////////////////// + /// Mode 1 Instrument Sect + if (nInstrPSolved) + { + + lset = ix * nparam + nInstrVal; + long iiVal = ix * nInstrPSolved; + for (int inInstr = 0; inInstr < nInstrPSolved; inInstr++) + { + ixInstr = offLocalInstr + instrCol[iiVal + inInstr]; + sum = sum + systemMatrix[lset] * vVect[ixInstr]; + lset++; + } + } + ////////////////////////////////////////////////////// + /// Mode 1 Global sect + if (nGlobP) + { + lset = ix * nparam + nGlobVal; + for (long inGlob = offLocalGlob; inGlob < offLocalGlob + nGlobP; inGlob++) + { + sum = sum + systemMatrix[lset] * vVect[inGlob]; + lset++; + } + } + ////////////////////////////////////////////////////// + return sum; +} +void aprodM2AstroP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, long int *matrixIndex, double *knownTerms){ + + int myid = comlsqr.myid; + short nAstroPSolved = comlsqr.nAstroPSolved; + long nparam = comlsqr.parOss; + int multMI = comlsqr.multMI; + long miValAstro = 0; + long offLocalAstro = 0; + double taskLocalSum=0.; + long jstartAstro = 0; + long lset; + offLocalAstro = comlsqr.mapStar[myid][0] * nAstroPSolved; //Offset on my mstars + jstartAstro = miValAstro - offLocalAstro; + // lset=comlsqr.mapForThread[nt][0]*nparam+(ix-comlsqr.mapForThread[nt][0])*nparam; + lset=ix*nparam; + + if (matrixIndex[multMI * ix] != miValAstro) + { + miValAstro = matrixIndex[multMI * ix]; + jstartAstro = miValAstro - offLocalAstro; + } + for (long jx = jstartAstro; jx < jstartAstro + nAstroPSolved; jx++) + { + + taskLocalSum = systemMatrix[lset] * knownTerms[ix]; + //vVect[jx] = 0.000001; + if(jx == 1 && false) + { + printf("nAstroPSolved nt:%d ix:%ld vVect[jx]:%f\n\n",nt,ix,vVect[jx] ); + + } + vVect[jx] += taskLocalSum; + lset++; + } //for jx + return; +} + +void aprodM2AttP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, long int *matrixIndex, double *knownTerms){ + + int myid = comlsqr.myid; + short nAstroPSolved = comlsqr.nAstroPSolved; + long localAstroMax = comlsqr.VrIdAstroPDimMax * nAstroPSolved; + long offsetAttParam = comlsqr.offsetAttParam; + short nAttParAxis = comlsqr.nAttParAxis; + long nparam = comlsqr.parOss; + int multMI = comlsqr.multMI; + long mix; + long miValAstro = 0; + long offLocalAstro = 0; + double taskLocalSum=0.; + long jstartAstro = 0; + long lset; + long offj = (localAstroMax - offsetAttParam); + long vVix; + short nAttAxes = comlsqr.nAttAxes; + double localSum; + + long nDegFreedomAtt = comlsqr.nDegFreedomAtt; + + offLocalAstro = comlsqr.mapStar[myid][0] * nAstroPSolved; //Offset on my mstars + jstartAstro = miValAstro - offLocalAstro; + + lset = nparam * ix + nAstroPSolved; + mix = matrixIndex[multMI * ix + (multMI - 1)] + offj; + for (int ly = 0; ly < nAttAxes; ly++) + { + vVix = mix + ly * nDegFreedomAtt; + if(vVix == 1) + { + printf("nAttP nt %d %ld\n\n",nt,ix); + + } + for (int lx = 0; lx < nAttParAxis; lx++) + { + localSum = systemMatrix[lset] * knownTerms[ix]; + // #pragma omp atomic + // vVect[vVix] = 0.000001; + vVect[vVix] += localSum; + lset++; + vVix++; + } //for lx + } //for ly + return; + +} + +void aprodM2InstrP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, int *instrCol, double *knownTerms){ +int myid = comlsqr.myid; +short nAstroPSolved = comlsqr.nAstroPSolved; +long localAstroMax = comlsqr.VrIdAstroPDimMax * nAstroPSolved; +long offsetAttParam = comlsqr.offsetAttParam; +short nAttP = comlsqr.nAttP; +short nInstrPSolved = comlsqr.nInstrPSolved; +long nparam = comlsqr.parOss; +long miValAstro = 0; +long offLocalAstro = 0; +long jstartAstro = 0; +long lset; +long offsetInstrParam = comlsqr.offsetInstrParam; +long offj = offsetInstrParam + (localAstroMax - offsetAttParam); +long vVix; +long iix; + double localSum; + + +offLocalAstro = comlsqr.mapStar[myid][0] * nAstroPSolved; //Offset on my mstars +jstartAstro = miValAstro - offLocalAstro; +int offLset = nAstroPSolved + nAttP; + + lset = nparam * ix + offLset; + iix = ix * nInstrPSolved; + for (int ly = 0; ly < nInstrPSolved; ly++) + { + vVix = offj + instrCol[iix + ly]; + if(vVix == 1) + { + printf("nOfInstrConstr nt %d %ld\n\n",nt,ix); + + } + localSum = systemMatrix[lset] * knownTerms[ix]; + //#pragma omp atomic + //vVect[vVix] = 0.000001; + vVect[vVix] += localSum; + lset++; + } //for ly + return; + +} +void aprodM2GlobP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, double *knownTerms){ +int myid = comlsqr.myid; +short nAstroPSolved = comlsqr.nAstroPSolved; +long localAstroMax = comlsqr.VrIdAstroPDimMax * nAstroPSolved; +long offsetAttParam = comlsqr.offsetAttParam; +short nAttP = comlsqr.nAttP; +short nInstrPSolved = comlsqr.nInstrPSolved; +long nparam = comlsqr.parOss; +long lset; +long offsetGlobParam = comlsqr.offsetGlobParam; +short nGlobP = comlsqr.nGlobP; + +long vVix; + double localSum; + + + + int offLset = nAstroPSolved + nAttP + nInstrPSolved; + long offj = offsetGlobParam + (localAstroMax - offsetAttParam); + + lset = nparam * ix + offLset; + for (long ly = 0; ly < nGlobP; ly++) + { + vVix = offj + ly; + if(vVix == 1) + { + printf("nGlobP nt %ld\n\n",ix); + + } + localSum = systemMatrix[lset] * knownTerms[ix]; + vVect[vVix] += localSum; + lset++; + } //for ly + + + + + +} +/* + int myid = comlsqr.myid; + short nAstroPSolved = comlsqr.nAstroPSolved; + long localAstroMax = comlsqr.VrIdAstroPDimMax * nAstroPSolved; + long nDegFreedomAtt = comlsqr.nDegFreedomAtt; + short nAttParAxis = comlsqr.nAttParAxis; + short nAttP = comlsqr.nAttP; + short nGlobP = comlsqr.nGlobP; + short nInstrPSolved = comlsqr.nInstrPSolved; + long offsetAttParam = comlsqr.offsetAttParam; + long offsetInstrParam = comlsqr.offsetInstrParam; + long offsetGlobParam = comlsqr.offsetGlobParam; + long nparam = comlsqr.parOss; + short nAttAxes = comlsqr.nAttAxes; + int multMI = comlsqr.multMI; + long miValAstro = 0; + long miValAtt = 0; + long jstartAtt = 0; + long offLocalAstro = 0; + long offLocalAtt = 0; + long offLocalInstr = 0; //Offset on Instruments + double taskLocalSum=0.; + long jstartAstro = 0; + long ixInstr = 0; + int nInstrVal = 0; + double sum=0.; + long lset; + offLocalInstr = offsetInstrParam + (localAstroMax - offsetAttParam); //Offset on Instruments + nInstrVal = nAstroPSolved + nAttP; + offLocalAstro = comlsqr.mapStar[myid][0] * nAstroPSolved; //Offset on my mstars + offLocalAtt = localAstroMax - offsetAttParam; //Offset on attitude + long offLocalGlob = offsetGlobParam + (localAstroMax - offsetAttParam); //Offset on GlobP + int nGlobVal = nAstroPSolved + nAttP + nInstrPSolved; + jstartAstro = miValAstro - offLocalAstro; + lset=comlsqr.mapForThread[nt][0]*nparam+(ix-comlsqr.mapForThread[nt][0])*nparam; + + */ diff --git a/util.h b/util.h old mode 100755 new mode 100644 index d5ae47f..cd64880 --- a/util.h +++ b/util.h @@ -102,7 +102,8 @@ struct comData { int timeCPR, timeLimit, itnCPR,itnCPRstop,itnCPRend, itnLimit,itn,noCPR; long offsetCMag,offsetCnu,offsetCdelta_eta,offsetCDelta_eta_1,offsetCDelta_eta_2; long offsetCDelta_eta_3,offsetCdelta_zeta,offsetCDelta_zeta_1,offsetCDelta_zeta_2; - int nthreads; + int nthreads=1; + int ntasks; long **mapForThread; int nSubsetAtt, nSubsetInstr; int NOnSubsetAtt, NOnSubsetInstr; @@ -116,6 +117,8 @@ struct comData { char *outputDir; double nullSpaceAttfact,extConstrW,barConstrW; time_t totSec; + double **vVect_aux_AttP; + double **vVect_aux_InstP; }; @@ -209,4 +212,10 @@ double legendre(int deg, double x); int computeInstrConstr (struct comData comlsqr,double * instrCoeffConstr,int * instrColsConstr,int * instrConstrIlung); void swapInstrCoeff(double * instrCoeff, long repeat, long nrows); float simfullram(long &nStar, long &nobs, float memGlobal, int nparams, int nAttParam, int nInstrParam); +double aprodM1Obs(long ix,struct comData comlsqr, double *vVect, double *systemMatrix, long int *matrixIndex, int *instrCol); +void aprodM2AstroP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, long int *matrixIndex, double *knownTerms); +void aprodM2AttP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, long int *matrixIndex, double *knownTerms); +void aprodM2InstrP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, int *instrCol, double *knownTerms); +void aprodM2GlobP(long ix,int nt, struct comData comlsqr, double *vVect, double *systemMatrix, double *knownTerms); + #endif -- GitLab