@@ -57,6 +57,8 @@ int main(int argc, char* argv[]) {
5757 bool no_flux = false ; // do not generate fluxes
5858 bool no_stellar = false ; // do not generate fluxes from stellar origin
5959 bool no_dust = false ; // do not generate fluxes from dust origin
60+ bool no_random = false ; // disable all randomization of parameters
61+ // (just passive, M*, z, and position + pos angle)
6062
6163 // Save the full spectrum of each galaxy to a file
6264 // Warning: the current implementation will consume a lot of RAM memory
@@ -113,8 +115,8 @@ int main(int argc, char* argv[]) {
113115 read_args (argc, argv, arg_list (
114116 ra0, dec0, area, mmin, maglim, zmin, zmax, name (bin_dz, " dz" ), min_dz,
115117 name (bin_dm, " dm" ), ms_disp,
116- no_pos, no_clust, no_flux, no_stellar, no_dust, no_passive_lir, save_sed ,
117- name (mass_func_file, " mass_func" ),
118+ no_pos, no_clust, no_flux, no_stellar, no_dust, no_passive_lir, no_random ,
119+ save_sed, name (mass_func_file, " mass_func" ),
118120 name (ir_lib_file, " ir_lib" ), name (opt_lib_file, " opt_lib" ),
119121 name (out_file, " out" ), name (filter_db_file, " filter_db" ),
120122 verbose, name (tseed, " seed" ), name (tcosmo, " cosmo" ),
@@ -996,13 +998,15 @@ int main(int argc, char* argv[]) {
996998 // Calibrated from Lang et al. (2014), assuming no redshift evolution
997999 out.bt .resize (ngal);
9981000
999- out.bt [ida] = clamp (
1000- e10 (0.27 *(out.m [ida] - 10.0 ) - 0.7 + 0.2 *randomn (seed, nactive)), 0.0 , 1.0
1001- );
1001+ out.bt [ida] = e10 (0.27 *(out.m [ida] - 10.0 ) - 0.7 );
1002+ out.bt [idp] = e10 (0.1 *(out.m [idp] - 10.0 ) - 0.3 );
10021003
1003- out.bt [idp] = clamp (
1004- e10 (0.1 *(out.m [idp] - 10.0 ) - 0.3 + 0.2 *randomn (seed, npassive)), 0.0 , 1.0
1005- );
1004+ // Add random scatter
1005+ if (!no_random) {
1006+ out.bt *= e10 (0.2 *randomn (seed, ngal));
1007+ }
1008+
1009+ out.bt = clamp (out.bt , 0.0 , 1.0 );
10061010
10071011 out.m_bulge = out.m + log10 (out.bt );
10081012 vec1u idnf = where (!is_finite (out.m_bulge ));
@@ -1032,8 +1036,11 @@ int main(int argc, char* argv[]) {
10321036 {0.0 , 0.0 , 165.0 , 428.0 , 773.0 , 914.0 , 1069.0 , 1191.0 , 1154.0 , 1067.0 , 639.0 , 450.0 };
10331037 out.bulge_ratio = random_pdf (seed, bulge_ratio_x, bulge_ratio_p, ngal);
10341038
1035- out.bulge_radius = 8.0 *e10 (-1.3 *log10 (1.0 +out.z ) + 0.56 *(out.m - 11.25 )
1036- + 0.2 *randomn (seed, ngal));
1039+ out.bulge_radius = 8.0 *e10 (-1.3 *log10 (1.0 +out.z ) + 0.56 *(out.m - 11.25 ));
1040+
1041+ if (!no_random) {
1042+ out.bulge_radius *= e10 (0.2 *randomn (seed, ngal));
1043+ }
10371044
10381045 // Calibration from n<1.5 galaxies and M* > 9.0
10391046 vec1f disk_ratio_x =
@@ -1046,13 +1053,19 @@ int main(int argc, char* argv[]) {
10461053 double zmid = 1.7 ;
10471054 vec1u idhz = where (out.z > zmid);
10481055 fz[idhz] = -0.7 *log10 ((1.0 + out.z [idhz])/(1.0 + zmid)) - 0.3 *log10 (1.0 + zmid);
1049- out.disk_radius = 2.8 *e10 (fz + 0.2 *(out.m - 9.35 )
1050- + 0.25 *randomn (seed, ngal));
1056+ out.disk_radius = 2.8 *e10 (fz + 0.2 *(out.m - 9.35 ));
1057+
1058+ if (!no_random) {
1059+ out.disk_radius *= e10 (0.25 *randomn (seed, ngal));
1060+ }
10511061
10521062 // Use similar size for bulges of disk-dominated galaxies
10531063 vec1u idd = where (out.bt < 0.5 );
1054- out.bulge_radius [idd] = 2.8 *e10 (fz[idd] + 0.2 *(out.m [idd] - 9.35 )
1055- + 0.25 *randomn (seed, idd.size ()));
1064+ out.bulge_radius [idd] = 2.8 *e10 (fz[idd] + 0.2 *(out.m [idd] - 9.35 ));
1065+
1066+ if (!no_random) {
1067+ out.bulge_radius [idd] *= e10 (0.25 *randomn (seed, idd.size ()));
1068+ }
10561069
10571070 vec1d psize = propsize (out.z , cosmo);
10581071 out.disk_radius /= psize;
@@ -1075,18 +1088,18 @@ int main(int argc, char* argv[]) {
10751088
10761089 out.sfr [ida] = sfrms[ida];
10771090
1078- // Add dispersion
1079- out.sfr [ida] += ms_disp*randomn (seed, nactive);
1080-
1081- // Add starbursts
1082- vec1u idsb = where (random_coin (seed, 0.033 , nactive));
1083- out.sfr [ida[idsb]] += 0.72 ;
1084-
10851091 // Passive galaxies
10861092 out.sfr [idp] = min (sfrms[idp], 0.5 *(out.m [idp] - 11 ) + az[idp] - 0.6 );
10871093
1088- // Add dispersion
1089- out.sfr [idp] += 0.4 *randomn (seed, npassive);
1094+ if (!no_random) {
1095+ // Add dispersion
1096+ out.sfr [ida] += ms_disp*randomn (seed, nactive);
1097+ out.sfr [idp] += 0.4 *randomn (seed, npassive);
1098+
1099+ // Add starbursts
1100+ vec1u idsb = where (random_coin (seed, 0.033 , nactive));
1101+ out.sfr [ida[idsb]] += 0.72 ;
1102+ }
10901103
10911104 // Compute RSB and get final SFR in linear units
10921105 out.rsb = out.sfr - sfrms;
@@ -1102,7 +1115,11 @@ int main(int argc, char* argv[]) {
11021115 double airx = 1.2 ;
11031116 double ss = 0.45 , so = 0.35 ;
11041117 vec1f slope = ss*min (out.z , 3.0 ) + so;
1105- out.irx = e10 (slope*(out.m - am) + airx + 0.4 *randomn (seed, ngal));
1118+ out.irx = e10 (slope*(out.m - am) + airx);
1119+
1120+ if (!no_random) {
1121+ out.irx *= e10 (0.4 *randomn (seed, ngal));
1122+ }
11061123
11071124 if (no_passive_lir) {
11081125 out.irx [idp] = 0.0 ;
@@ -1119,32 +1136,50 @@ int main(int argc, char* argv[]) {
11191136 out.rfuv_disk .resize (ngal);
11201137 out.rfuv_bulge .resize (ngal);
11211138
1122- auto gen_blue = [&seed](const vec1f& m, const vec1f& z, vec1f& uv, vec1f& vj) {
1139+ auto gen_blue = [&seed,no_random ](const vec1f& m, const vec1f& z, vec1f& uv, vec1f& vj) {
11231140 // Calibrate "UVJ vector" from mass and redshift
11241141 vec1f a0 = 0.58 *erf (m-10 ) + 1.39 ;
11251142 vec1f as = -0.34 + 0.3 *max (m-10.35 , 0.0 );
11261143 vec1f a = min (a0 + as*z, 2.0 );
1127- vec1d rnd_amp = 0.3 *clamp (z-1.0 , 0 , 1 )*clamp (1.0 - abs (m - 10.3 ), 0 , 1 )
1128- + 0.1 + 0.05 *clamp (z-1.0 , 0 , 1 );
1129- a += rnd_amp*randomn (seed, m.size ());
1144+
1145+ if (!no_random) {
1146+ vec1d rnd_amp = 0.3 *clamp (z-1.0 , 0 , 1 )*clamp (1.0 - abs (m - 10.3 ), 0 , 1 ) + 0.1 + 0.05 *clamp (z-1.0 , 0 , 1 );
1147+ a += rnd_amp*randomn (seed, m.size ());
1148+ }
11301149
11311150 // Move in the UVJ diagram according to the UVJ vector
11321151 double slope = 0.65 ;
11331152 double theta = atan (slope);
1134- vj = 0.0 + a*cos (theta) + 0.12 *randomn (seed, m.size ());
1135- uv = 0.45 + a*sin (theta) + 0.12 *randomn (seed, m.size ());
1153+ vj = 0.0 + a*cos (theta);
1154+ uv = 0.45 + a*sin (theta);
1155+
1156+ if (!no_random) {
1157+ vj += 0.12 *randomn (seed, m.size ());
1158+ uv += 0.12 *randomn (seed, m.size ());
1159+ }
11361160
11371161 // Add an additional global color offset depending on redshift
11381162 uv += 0.4 *max ((0.5 - z)/0.5 , 0.0 );
11391163 vj += 0.2 *max ((0.5 - z)/0.5 , 0.0 );
11401164 };
11411165
1142- auto gen_red = [&seed](const vec1f& m, const vec1f& z, vec1f& uv, vec1f& vj) {
1166+ auto gen_red = [&seed,no_random ](const vec1f& m, const vec1f& z, vec1f& uv, vec1f& vj) {
11431167 double pvj = 1.25 , puv = 1.85 ;
1144- vec1f mspread = clamp (0.1 *(m - 11.0 ) + 0.1 *randomn (seed, m.size ()), -0.1 , 0.2 );
1168+ vec1f mspread = 0.1 *(m - 11.0 );
1169+
1170+ if (!no_random) {
1171+ mspread += 0.1 *randomn (seed, m.size ());
1172+ }
1173+
1174+ mspread = clamp (mspread, -0.1 , 0.2 );
1175+
1176+ vj = pvj + mspread;
1177+ uv = puv + mspread*0.88 ;
11451178
1146- vj = pvj + mspread + 0.1 *randomn (seed, m.size ());
1147- uv = puv + mspread*0.88 + 0.1 *randomn (seed, m.size ());
1179+ if (!no_random) {
1180+ vj += 0.1 *randomn (seed, m.size ());
1181+ uv += 0.1 *randomn (seed, m.size ());
1182+ }
11481183
11491184 // Add an additional global color offset depending on redshift
11501185 uv += 0.4 *max ((0.5 - z)/0.5 , 0.0 );
@@ -1157,7 +1192,10 @@ int main(int argc, char* argv[]) {
11571192 // Bulges of bulge-dominated galaxies are always red
11581193 // Other bulges have a 50% chance of being red
11591194 {
1160- vec1b red_bulge = out.bt > 0.6 || random_coin (seed, 0.5 , ngal);
1195+ vec1b red_bulge = out.bt > 0.6 ;
1196+ if (!no_random) {
1197+ red_bulge = red_bulge || random_coin (seed, 0.5 , ngal);
1198+ }
11611199
11621200 vec1f tuv, tvj;
11631201 vec1u idb = where (red_bulge);
@@ -1237,19 +1275,21 @@ if (!no_flux) {
12371275 out.tdust = 4.65 *(out.z -2.0 ) + 31.0
12381276 // Starbursts are warmer
12391277 + 6.6 *out.rsb
1240- // Add some random scatter
1241- + 3.0 *randomn (seed, ngal)
12421278 // Massive galaxies are colder (= downfall of SFE)
12431279 - 1.5 *min (0.0 , out.z -2.0 )*clamp (out.m - 10.7 , 0.0 , 1.0 );
12441280
12451281 out.ir8 = (1.95 *min (0.0 , out.z - 2.0 ) + 7.73 )
12461282 // Starburst have larger IR8
12471283 *e10 (0.43 *max (0.0 , out.rsb ))
1248- // Add some random scatter
1249- *e10 (0.1 *randomn (seed, ngal))
12501284 // Low-mass galaxies have larger IR8
12511285 *e10 (-1.8 *clamp (out.m - 10.0 , -1 , 0.0 ));
12521286
1287+ if (!no_random) {
1288+ // Add some random scatter
1289+ out.tdust += 3.0 *randomn (seed, ngal);
1290+ out.ir8 *= e10 (0.1 *randomn (seed, ngal));
1291+ }
1292+
12531293 out.ir8 = clamp (out.ir8 , 0.48 , 22.8 ); // range allowed by IR library
12541294 out.fpah = 0.267 /(out.ir8 - 0.217 ) - 0.0118 ;
12551295
@@ -1568,6 +1608,8 @@ void print_help() {
15681608 argdoc (" no_pos" , " [flag]" , " do not generate galaxy positions on the sky" );
15691609 argdoc (" no_clust" , " [flag]" , " do not generate clustering in galaxy positions" );
15701610 argdoc (" no_flux" , " [flag]" , " do not generate fluxes" );
1611+ argdoc (" no_random" , " [flag]" , " disable most randomization in the simulation, and use "
1612+ " fully deterministic recipes" );
15711613 print (" " );
15721614
15731615 print (" List of sky position related options:" );
0 commit comments