-
Notifications
You must be signed in to change notification settings - Fork 2
/
init_and_bounds.cpp
2223 lines (1795 loc) · 115 KB
/
init_and_bounds.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "aiolos.h"
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// CLASS SIMULATION
//
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Simulation class constructor and initializer of all the physics. Reads all simulation parameters from the *.par file, constructs all species using data from the *spc and linked
* *opa files.
*
* Computes the spatial grid, areas, volumes, wavelength grid. Initiates matrix solver objects, species data (around line 580) and radiative quantities.
*
* @param[in] filename_solo Parameter file without any other appendages, directory.
* @param[in] speciesfile_solo Species file without any other appendages, directory.
* @param[in] workingdir Working directory string
* @param[in] debug debug level from command line or param file
* @param[in] debug_cell Get detailed information for a specific cell (To be implemented by user..)
* @param[in] debug_steps Get detailed information for a specific timestep (To be implemented by user..)
*/
c_Sim::c_Sim(string filename_solo, string speciesfile_solo, string workingdir, int debug, int debug_cell, int debug_steps) {
if(debug > 0) cout<<"Init position 0."<<endl;
steps = -1;
this->debug = debug ;
this->debug_cell = debug_cell;
this->debug_steps= debug_steps;
simname = filename_solo;
this->workingdir = workingdir;
string filename = workingdir + filename_solo;
parfile = workingdir + filename_solo;
if(speciesfile_solo.compare("default.spc")==0)
speciesfile_solo = read_parameter_from_file<string>(filename,"SPECIES_FILE", debug, "default.spc").value; //The program always needs to know some information about the species used.
cout<<" Starting construction of simulation. Attempting to find required speciesfile = "<<speciesfile_solo<<endl;
speciesfile = workingdir + speciesfile_solo;
cout<<" Opening parameter file "<<filename<<endl;
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Numerical
//
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
double dx0;
type_of_grid = read_parameter_from_file<int>(filename,"PARI_GRID_TYPE", debug, 0).value; //Spacing type of grid. Linear, log, bi-log etc. More in enum.h
domain_min = read_parameter_from_file<double>(filename,"PARI_DOMAIN_MIN", debug).value; //Smallest value of 1-D domain in cm
domain_max = read_parameter_from_file<double>(filename,"PARI_DOMAIN_MAX", debug).value; //Largest value of 1-D domain in cm
geometry = read_parameter_from_file<Geometry>(filename, "PARI_GEOMETRY", debug, Geometry::cartesian).value; //Cartesian, Polar, Spherical. Determines differentials. More in enum.h
order = read_parameter_from_file<IntegrationType>(filename, "PARI_ORDER", debug, IntegrationType::second_order).value; //Spatial order of differentials.
num_bands_in = read_parameter_from_file<int>(filename,"PARI_NUM_BANDS", debug, 1).value; //Number of instellation bands. Low performance impact.
num_bands_out = read_parameter_from_file<int>(filename,"NUM_BANDS_OUT", debug, num_bands_in).value; //Number of outgoing radiation bands. Enormous performance impact.
lambda_min_in = read_parameter_from_file<double>(filename,"PARI_LAM_MIN", debug, 1e-1).value; //Minimum ingoing, non-zero limit of the wavelength domain in microns.
lambda_max_in = read_parameter_from_file<double>(filename,"PARI_LAM_MAX", debug, 10.).value; //Maximum ingoing, non-inf limit of the wavelength domain in microns.
//Note how by default there is another band between 0 and lambda_min_in, and another band lamda_max_in and infty, if the band numbers are high enough
lambda_per_decade_in= read_parameter_from_file<double>(filename,"PARI_LAM_PER_DECADE", debug, 10.).value; //Log-equidistant spacing in wavelngth
lambda_min_out = read_parameter_from_file<double>(filename,"PARI_LAM_MIN_OUT", debug, lambda_min_in).value;
lambda_max_out = read_parameter_from_file<double>(filename,"PARI_LAM_MAX_OUT", debug, lambda_max_in).value;
//Note how by default there is another band between 0 and lambda_min_out, and another band lamda_max_out and infty, if the band numbers are high enough
lambda_per_decade_out= read_parameter_from_file<double>(filename,"PARI_LAM_PER_DECADE_OUT", debug, lambda_per_decade_in).value;
fluxfile = read_parameter_from_file<string>(filename,"FLUX_FILE", debug, "---").value; //File to read in the wavelength-dependent data of the
fluxmultiplier = read_parameter_from_file<double>(filename,"FLUX_MULTIPLIER", debug, 1.).value; //Wavelength-constant multiplier for all top-of-atmosphere band fluxes
star_mass = read_parameter_from_file<double>(filename,"PARI_MSTAR", debug, 1.).value; //Mass of the star in solar masses
//star_mass *= msolar;
init_star_mass = msolar * read_parameter_from_file<double>(filename,"INIT_MSTAR", debug, star_mass).value;
star_mass *= msolar;
ramp_star_mass_t0 = read_parameter_from_file<double>(filename,"RAMP_MSTAR_T0", debug, 0.).value;
ramp_star_mass_t1 = read_parameter_from_file<double>(filename,"RAMP_MSTAR_T1", debug, 1.).value;
T_star = read_parameter_from_file<double>(filename,"PARI_TSTAR", debug, 5777.).value; //tau=2/3 temperature of the star, i.e. Teff in K
R_star = read_parameter_from_file<double>(filename,"PARI_RSTAR", debug, 0.).value; //radius of the star in solar radii
UV_star = read_parameter_from_file<double>(filename,"PARI_UVSTAR", debug, 0.).value; // UV luminosity of the star, used if no flux file is given, in erg/s
X_star = read_parameter_from_file<double>(filename,"PARI_XSTAR", debug, 0.).value; //X-ray luminosity of the star, not used currently
Lyalpha_star = read_parameter_from_file<double>(filename,"PARI_LYASTAR", debug, 0.).value; // Not used currently
planet_semimajor= read_parameter_from_file<double>(filename,"PARI_PLANET_DIST", debug, 1.).value; //Distance to primary black-body in AU
R_other = read_parameter_from_file<double>(filename,"R_OTHER", debug, 0.).value; //Second bolometric black-body source (i.e. second star or giant planet host) in stellar radii
T_other = read_parameter_from_file<double>(filename,"T_OTHER", debug, 0.).value; //Temperature of other black-body in K
d_other = read_parameter_from_file<double>(filename,"D_OTHER", debug, 1.).value; // Distance to other black-body in AU
T_int = read_parameter_from_file<double>(filename,"PARI_TINT", debug, 0.).value; //Internal planetary temperature at inner boundary. T_int in Guillot2010. in K.
// old notation.
if (T_int==0)
T_int = read_parameter_from_file<double>(filename,"PARI_TPLANET", debug, 0.).value; //Internal planetary temperature at inner boundary. T_int in Guillot2010. in K.
use_planetary_temperature = read_parameter_from_file<int>(filename,"USE_PLANET_TEMPERATURE", debug, 0).value;//Add the T_int heating to the lower boundary cell?
core_cv = read_parameter_from_file<double>(filename,"PARI_CORE_CV", debug, 0).value; //Heat capacity of the core
T_planet = read_parameter_from_file<double>(filename,"PARI_TPLANET_INIT", debug, 0).value; //To be unused?
//Note that using T_planet might require smaller timesteps (if they are not already restricted by CFL), in those cases use max_timestep_change to limit the dt increase
radiation_matter_equilibrium_test = read_parameter_from_file<int>(filename,"RAD_MATTER_EQUI_TEST", debug, 0).value; //Unused/only for tests
radiation_diffusion_test_linear = read_parameter_from_file<int>(filename,"RAD_DIFF_TEST_LIN", debug, 0).value; //Unused/only for tests
radiation_diffusion_test_nonlinear= read_parameter_from_file<int>(filename,"RAD_DIFF_TEST_NLIN", debug, 0).value; //Unused/only for tests
couple_J_into_T = read_parameter_from_file<int>(filename,"COUPLE_J_INTO_T", debug, 1).value; //Unused/only for tests
if(debug > 0) cout<<"Using integration order "<<order<<" while second order would be "<<IntegrationType::second_order<<endl;
if (order == IntegrationType::first_order)
num_ghosts = 1 ;
else
num_ghosts = 2 ;
if(type_of_grid == 0) {
dx0 = read_parameter_from_file<double>(filename,"PARI_DOMAIN_DX", debug).value; //For uniform grid, resolution element size
num_cells = (int)((domain_max - domain_min)/dx0);
cout<<"Domain specifics: "<<domain_min<<" | . . . "<<num_cells<<" uniform cells . . . | "<<domain_max<<endl;
}
else {
cells_per_decade = read_parameter_from_file<double>(filename,"PARI_CELLS_PER_DECADE", debug).value; //For logarithmic grid, number cells per decade in resolution
num_cells = (int) ( (log10f(domain_max) - log10f(domain_min)) * cells_per_decade );
dx0 = domain_min;
if(type_of_grid==2) {
grid2_transition = read_parameter_from_file<double>(filename,"GRID2_TRANSITION", debug, 99.e99).value; //For bi-logarithmic grid (two different resolution regions), define transition boundary
grid2_cells_per_decade = read_parameter_from_file<double>(filename,"GRID2_CELLS_PER_DECADE", debug, 10).value; // For bi-logarithmic grid, number cells per decade in resolution in second region at large r (first region sits at small r)
num_cells = (int) ( (log10f(grid2_transition) - log10f(domain_min)) * cells_per_decade );
grid2_transition_i = num_cells + num_ghosts;
num_cells += (int) ( (log10f(domain_max) - log10f(grid2_transition)) * grid2_cells_per_decade );
}
cout<<"Domain specifics: "<<domain_min<<" | . . . "<<num_cells<<" nonuniform cells . . . | "<<domain_max<<endl;
}
reverse_hydrostat_constrution = read_parameter_from_file<int>(filename,"REVERSE_HYDROSTAT_CONSTRUCTION", debug, 0).value; //If false, or zero, construct density from large r to small r.
//Otherwise reversed. First density is the PARI_INIT_DATA_U1parameter.
init_wind = read_parameter_from_file<int>(filename,"PARI_INIT_WIND", debug, 0).value; //Initialize a step in density at init_sonic_radius of variable magnitude.
//Magnitude of density jump is set by species dependent parameter in *spc file in column 7 "initial density excess". If init_sonic_radius is negative, then do nothing.
init_sonic_radius = read_parameter_from_file<double>(filename,"INIT_SONIC_RADIUS", debug, -1e10).value;
//
// Check that cell number looks fine. Shoutout if its not.
//
if( !(num_cells > 0 && num_cells < 999999) ) {
std::stringstream err ;
err<<" WARNING! Something seems wrong with the number of cells required. num_cells = "<<num_cells<<endl;
throw std::invalid_argument(err.str()) ;
}
if(debug > 0) cout<<"Init: Finished reading grid parameters."<<endl;
cflfactor = read_parameter_from_file<double>(filename,"PARI_CFLFACTOR", debug, 0.9).value; //Multiplier on the cfl timestep length
t_max = read_parameter_from_file<double>(filename,"PARI_TIME_TMAX", debug, 1e0).value; // Simulate until t=t_max in seconds.
dt_max = read_parameter_from_file<double>(filename,"PARI_DTMAX", debug, 1e99).value; // Limit the largest possible timestep size in seconds.
max_timestep_change = read_parameter_from_file<double>(filename,"MAX_TIMESTEP_CHANGE", debug, 1.1).value; //Max. change of timestep per following timestep in s.
dt_min_init = read_parameter_from_file<double>(filename,"DT_MIN_INIT", debug, 1e-20).value; //Initial dt in s
output_time = read_parameter_from_file<double>(filename,"PARI_TIME_OUTPUT", debug, 1e99).value; //Create an output every xxx simulated seconds.
output_time_offset = read_parameter_from_file<double>(filename,"TIME_OUTPUT_OFFSET", debug, 0.).value; //Create outputs every PARI_TIME_OUTPUT but only starting after offset, in s
monitor_time = read_parameter_from_file<double>(filename,"PARI_TIME_DT", debug).value; //Put measurements into the monitor file every xx s
CFL_break_time = read_parameter_from_file<double>(filename,"CFL_BREAK_TIME", debug, std::numeric_limits<double>::max()).value ; //Use PARI_CFLFACTOR if t<CLF_break_time. Otherwise, set cflfactor to 0.9
energy_epsilon = read_parameter_from_file<double>(filename,"ENERGY_EPSILON", debug, 0.01).value; //Relative allowed change of internal energy in any single grid cell. Limits timestep size additional to the CFL condition.
globalTime = 0.0;
timecount = 0;
if(t_max / monitor_time > 1e6) {
char b;
cout<<" WARNING! Specified t_max and t_dt will result in "<<(t_max / monitor_time)<<" entries in the monitor file."<<endl<<" This might create a large file and/or impact performance significantly. Press the any key to continue."<<endl;
cin>>b;
}
if(debug > 0) cout<<"Init: Finished reading time parameters."<<endl;
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Control parameters for users
//
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
problem_number = read_parameter_from_file<int>(filename,"PARI_PROBLEM_NUMBER", debug).value; //0==gas tube, 1==planet run
use_self_gravity = read_parameter_from_file<int>(filename,"PARI_SELF_GRAV_SWITCH", debug, 0).value;//Gravitational field of gas in domain added to potential?
use_tides = read_parameter_from_file<int>(filename,"USE_TIDES", debug, 0).value; //Use the tidal field from the first central object (i.e. star_mass, R_star etc)?
use_linear_gravity= read_parameter_from_file<int>(filename,"PARI_LINEAR_GRAV", debug, 0).value; //Linear acceleration ~r instead of 1/r^2
use_rad_fluxes = read_parameter_from_file<int>(filename,"PARI_USE_RADIATION", debug, 0).value; //Switch to turn on the radiation module
use_convective_fluxes = read_parameter_from_file<int>(filename,"USE_CONVECTION", debug, 0).value; //Switch to turn on convective energy transport in the radiation module
K_zz_init = read_parameter_from_file<double>(filename,"KZZ_INIT", debug, 0.).value; //Initial atmospheric mixing parameter in cm^2/s
convect_boundary_strength = read_parameter_from_file<double>(filename,"CONVECT_BOUNDARY_STRENGTH", debug, 1.1).value; //Unused currently.
use_collisional_heating = read_parameter_from_file<int>(filename,"PARI_USE_COLL_HEAT", debug, 1).value; //Switch on collisional energy exchange between species
use_drag_predictor_step = read_parameter_from_file<int>(filename, "PARI_SECONDORDER_DRAG", debug, 0).value; //Switch on drag predictor substep
alpha_collision = read_parameter_from_file<double>(filename,"PARI_ALPHA_COLL", debug, 1.).value; //Multiplier for collision alphas
alpha_collision_ions = read_parameter_from_file<double>(filename,"PARI_ALPHA_IONS", debug, 1.).value; //Multiplier for collision alphas for ions
max_mdot = read_parameter_from_file<double>(filename,"MAX_MDOT", debug, -1.).value; //Max negative mdot through outer boundary in g/s
rad_energy_multiplier=read_parameter_from_file<double>(filename,"PARI_RAD_MULTIPL", debug, 1.).value; //Only for tests. Unused currently.
collision_model = read_parameter_from_file<char>(filename,"PARI_COLL_MODEL", debug, 'P').value; //Collision model. P=physical collision rates (i.e. Schunk&Nagy). C=constant collision rate of value PARI_ALPHAS_COLL
opacity_model = read_parameter_from_file<char>(filename,"PARI_OPACITY_MODEL", debug, 'C').value; //Opacity model. List in opacities.cpp line 90.
use_avg_temperature = read_parameter_from_file<int>(filename,"USE_AVG_T", debug, 0).value; //Compute avg c_v rho T and use that as T_avg
avg_temperature_t0 = read_parameter_from_file<double>(filename,"avg_temperature_t0", debug, 1e99).value; //All T_s = T_avg before t0. Between t0 and t1 a ramp-down begins
avg_temperature_t1 = read_parameter_from_file<double>(filename,"avg_temperature_t1", debug, 1e99).value; //All T_s remain T_s after t1. T_avg is ignored after t1
cout<<" CHOSEN OPACITY MODEL = "<<opacity_model<<endl;
if(opacity_model == 'M')
init_malygin_opacities();
if(opacity_model == 'K') {
cout<<" Hybrid opacities selected. NOTE! that the input file expects in this mode two file names to be given for each species, one *aiopa for kR and kP, and *opa for kS."<<endl;
}
no_rad_trans = read_parameter_from_file<double>(filename,"NO_RAD_TRANS", debug, 1.).value; //Multiplier for strength for thermal radiative losses in radiation transport. Set to 1e-100 to emulate perfect energy-limited escape.
solve_for_j = read_parameter_from_file<int>(filename,"SOLVE_FOR_J", debug, 1).value; //Debugging parameter. Switch to zero for decoupling of T and J in simple rad transport
photocooling_multiplier = read_parameter_from_file<double>(filename,"PHOTOCOOL_MULTIPLIER", debug, 1.).value; //Multiplier for non-thermal cooling rates
photocooling_expansion = read_parameter_from_file<double>(filename,"PHOTOCOOL_EXPANSION", debug, 1.).value; //Multiplier for non-thermal second order cooling rates
radiation_rampup_time = read_parameter_from_file<double>(filename,"RAD_RAMPUP_TIME", debug, 0.).value; //Ramp up the irradiation in all bands smoothly over xxx seconds.
init_radiation_factor = read_parameter_from_file<double>(filename,"INIT_RAD_FACTOR", debug, 0.).value; //Unused
//radiation_solver = read_parameter_from_file<int>(filename,"RADIATION_SOLVER", debug, 0).value; //replaced by use_rad_fluxes
closed_radiative_boundaries = read_parameter_from_file<int>(filename,"PARI_CLOSED_RADIATIVE_BOUND", debug, 0).value; //Reflect thermal radiation at outer boundaries?
const_opacity_solar_factor = read_parameter_from_file<double>(filename,"CONSTOPA_SOLAR_FACTOR", debug, 1.).value; //Multiplier for all stellar opacities (independent of opacity model)
const_opacity_rosseland_factor = read_parameter_from_file<double>(filename,"CONSTOPA_ROSS_FACTOR", debug, 1.).value; //Multiplier for all rosseland opacities (")
const_opacity_planck_factor = read_parameter_from_file<double>(filename,"CONSTOPA_PLANCK_FACTOR", debug, 1.).value; //Multiplier for all planck opacities (")
temperature_model = read_parameter_from_file<char>(filename,"INIT_TEMPERATURE_MODEL", debug, 'P').value; //Initialize temperature as adiabatic+constant (P) or constant (C)
friction_solver = read_parameter_from_file<int>(filename,"FRICTION_SOLVER", debug, 0).value; //0: no friction, 1: analytic (only for two species), 2: numerical
update_coll_frequently = read_parameter_from_file<int>(filename,"UPDATE_COLL_FREQUENTLY", debug, 1).value; //Switches on or off another update of collision rates after temperature and before temperature exchange update for rad solver==2. Important for code performance with many species
do_hydrodynamics = read_parameter_from_file<int>(filename,"DO_HYDRO", debug, 1).value; //Switch hydrodynamics, including its CFL condition on/off
start_hydro_time = read_parameter_from_file<double>(filename,"START_HYDRO_TIME", debug, -1.).value; //Hydro is started once globalTime > start_hydro_time and do_hydro == 1
photochemistry_level = read_parameter_from_file<int>(filename,"PHOTOCHEM_LEVEL", debug, 0).value; //1==C2Ray solver, 2==general photo and thermochemistry solver
dust_to_gas_ratio = read_parameter_from_file<double>(filename,"DUST_TO_GAS", debug, 0.).value; //dust-to-gas ratio for Semenov/Malygin opacities
temperature_floor = read_parameter_from_file<double>(filename,"TEMPERATURE_FLOOR", debug, 0.).value; //Limit the temperature to a minimum in radiation solver (negative T crashes can still occur due to negative pressures, whichever is found first)
max_temperature = read_parameter_from_file<double>(filename,"TEMPERATURE_MAX", debug, 9e99).value; //Limit the temperature to a maximum
use_chemistry = read_parameter_from_file<int>(filename,"DO_CHEM", debug, 0).value; //Unused currently.
use_total_pressure = read_parameter_from_file<int>(filename,"USE_TOTAL_PRESSURE", debug, 0).value; //Compute total pressure of all species? Unused currently.
coll_rampup_time = read_parameter_from_file<double>(filename,"COLL_RAMPUP_TIME", debug, 0.).value; //Ramp up collision rates gently from INIT_COLL_FACTOR to PARI_ALPHA_COLL in the rampup time
init_coll_factor = read_parameter_from_file<double>(filename,"INIT_COLL_FACTOR", debug, 0.).value;
chemistry_precision = read_parameter_from_file<double>(filename,"CHEM_PRECISION", debug, 1e-2).value; //Relative preicion for the number densities to be accepted by solver
chemistry_numberdens_floor = read_parameter_from_file<double>(filename,"CHEM_FLOOR", debug, 1e-20).value; //Lower number densities floor per cell, normalized to total cell dens
chemistry_maxiter = read_parameter_from_file<int>(filename,"CHEM_MAXITER", debug, 4).value; //Number of max chem solver iterations per timestep. Increase as 2^int
chemistry_miniter = read_parameter_from_file<int>(filename,"CHEM_MINITER", debug, 4).value; //Number of min chem solver iterations per timestep.
ion_precision = read_parameter_from_file<double>(filename,"ION_PRECISION", debug, 1e-12).value; //Precision of brent solver for C2Ray number densities
ion_heating_precision = read_parameter_from_file<double>(filename,"ION_HEATING_PRECISION", debug, 1e-12).value; //Precision of brent solver for C2Ray heating rates
ion_maxiter = read_parameter_from_file<int>(filename,"ION_MAXITER", debug, 128).value; //Maxiter of brent solver for C2Ray number densities
ion_heating_maxiter = read_parameter_from_file<int>(filename,"ION_HEATING_MAXITER", debug, 128).value;//Maxiter of brent solver for C2Ray heating rates
intermediate_chemfloor_check = read_parameter_from_file<int>(filename,"INTERMEDIATE_CHEM_CHECK", debug, 0).value; //Check chem_floor in between iterations?
chem_momentum_correction = read_parameter_from_file<int>(filename,"CHEM_MOMENTUM_CORR", debug, 1).value; //Compute momentum transport due to ndot
chem_ekin_correction = read_parameter_from_file<int>(filename,"CHEM_EKIN_CORR", debug, 1).value; //Compute energy transport due to ndot
dt_skip_ichem = read_parameter_from_file<int>(filename,"CHEM_DT_SKIP", debug, 1).value; //Skip chemistry update every xxx timesteps in main loop. Accumulate timesteps until next chem solver call. Currently buggy.
right_extrap_press_multiplier =read_parameter_from_file<double>(filename,"BOUND_EXTRAP_MUL", debug, 1.0).value; //Hydrodynamic pressure extrapolation into ghost cell multiplier
dt_skip_dchem = 0.;
rad_solver_max_iter = read_parameter_from_file<int>(filename,"MAX_RAD_ITER", debug, 1).value; //Currently unused
xi_rad = read_parameter_from_file<double>(filename,"XI_RAD", debug, 2.).value; //Radiation Xi factor, see Fig. 5 in code paper.
bond_albedo = read_parameter_from_file<double>(filename,"BOND_ALBEDO", debug, 0.).value; //Bond albedo, Number between 0. and 1.
use_init_discont_smoothing = read_parameter_from_file<int>(filename,"INIT_DISCONT_SMOOTHING", debug, 0).value; //Smooths out discontinuities in the initial density profiles with a powerlaw. Applied before init_wind discontinuity is put in.
if(problem_number == 2)
monitor_output_index = num_cells/2;
else
monitor_output_index = 1;
if(problem_number==2) {
planet_mass = read_parameter_from_file<double>(filename,"PARI_PLANET_MASS", debug, 1).value; //in Earth masses
planet_mass *= mearth;
planet_position = read_parameter_from_file<double>(filename,"PARI_PLANET_POS", debug, 0.).value; //In spatial coordinates.
rs = read_parameter_from_file<double>(filename,"PARI_SMOOTHING_LENGTH", debug, 0.).value; //Gravitational smoothing length in rhill
rs_time = read_parameter_from_file<double>(filename,"PARI_SMOOTHING_TIME", debug, 0.).value; //Ramp-up time for smoothing length from 0 till PARI_SMOOTHING_LENGTH
rs_at_moment = 0.2;
} else {
planet_mass = read_parameter_from_file<double>(filename,"PARI_PLANET_MASS", debug, 0).value; //in Earth masses
planet_mass *= mearth;
planet_position = read_parameter_from_file<double>(filename,"PARI_PLANET_POS", debug, 0.).value; //inside the simulation domain
rs = read_parameter_from_file<double>(filename,"PARI_SMOOTHING_LENGTH", debug, 0.).value; //Gravitational smoothing length in hill
rs_time = read_parameter_from_file<double>(filename,"PARI_SMOOTHING_TIME", debug, 0.).value; //Time until we reach rs starting at rs_at_moment
rs_at_moment = 0.2;
}
if(use_self_gravity)
cout<<"WARNING: Self-gravity switched ON !!!"<<endl;
if(debug > 0) cout<<"Init: Finished reading gravity parameters"<<endl;
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Simulation data: Grid and variables
//
////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Increment num cells so that we have enough space for the ghosts
num_cells += 2*(num_ghosts-1) ;
x_i = np_zeros(num_cells+1); // The cell boundaries
x_i12 = np_zeros(num_cells+2); // The cell mid positions
x_iVC = np_zeros(num_cells+2); // The cell volumetric centres
surf = np_zeros(num_cells+1); // intercell surfaces
vol = np_zeros(num_cells+2); // cell volumes
dx = np_zeros(num_cells+2);
omegaplus = np_zeros(num_cells+2);
omegaminus = np_zeros(num_cells+2);
source_pressure_prefactor_left = np_zeros(num_cells+2);
source_pressure_prefactor_right = np_zeros(num_cells+2);
enclosed_mass = np_zeros(num_cells+2);
enclosed_mass_tmp = np_zeros(num_cells+2);
phi = np_zeros(num_cells+2);
//total_pressure = np_zeros(num_cells+2);
total_press_l = std::vector<double>(num_cells+2);
total_press_r = std::vector<double>(num_cells+2);
total_adiabatic_index = std::vector<double>(num_cells+2);
if(num_bands_in < 1) {
cout<<" In INIT RADIATION, invalid num_bands_in = "<<num_bands_in<<" changing to num_bands_in = 1."<<endl;
num_bands_in = 1;
}
if(num_bands_out < 1) {
cout<<" In INIT RADIATION, invalid num_bands_out = "<<num_bands_out<<" changing to num_bands_out = 1."<<endl;
num_bands_out = 1;
}
if(use_rad_fluxes == 2 && use_convective_fluxes == 1 ) {
cout<<" Simple radiative solver used, but with convection. Note that convection in this case is not implemented yet!"<<endl;
}
l_i_in = np_zeros(num_bands_in+1); // Wavelenght bin boundaries
l_i12_in = np_zeros(num_bands_in); // Wavelength bin midpoints or averages
l_i_out = np_zeros(num_bands_out+1); // Wavelenght bin boundaries
l_i12_out = np_zeros(num_bands_out); // Wavelength bin midpoints or averages
BAND_IS_HIGHENERGY = inp_zeros(num_bands_in); //We save wether a band is a highenergy band. This is important for which solver is activated.
l_i_in[0] = lminglobal/100.; //Transform wavelengths into microns
l_i_in[num_bands_in] = lmaxglobal/100.;
l_i_out[0] = lminglobal/100.; //Transform wavelengths into microns
l_i_out[num_bands_out] = lmaxglobal/100.;
/////////////////////////////////////////////////////////
////////////////////////////////Bands in
/////////////////////////////////////////////////////////
if(num_bands_in == 2) {
l_i_in[1] = 0.5*(lambda_max_in + lambda_min_in);
l_i12_in[0] = lambda_min_in;
l_i12_in[1] = lambda_max_in;
}
else if(num_bands_in > 2)
{
l_i_in[1] = lambda_min_in;
l_i_in[num_bands_in-1] = lambda_max_in;
double dlogl2 = pow(lambda_max_in/lambda_min_in, 1./(num_bands_in-2));
for(int b=2; b<num_bands_in-1; b++) {
l_i_in[b] = l_i_in[b-1] * dlogl2;
cout<<" in NUM_BANDS>2, b = "<<b<<" l_i_in[b] = "<<l_i_in[b]<<endl;
}
for(int b=0; b<num_bands_in; b++) {
l_i12_in[b] = pow( 10., 0.5 * (std::log10(l_i_in[b]) + std::log10(l_i_in[b+1])));
}
}
/////////////////////////////////////////////////////////
////////////////////////////////Bands out
/////////////////////////////////////////////////////////
if(num_bands_out == 2) {
l_i_out[1] = 0.5*(lambda_max_out + lambda_min_out);
l_i12_out[0] = lambda_min_out;
l_i12_out[1] = lambda_max_out;
}
else if(num_bands_out > 2)
{
l_i_out[1] = lambda_min_out;
l_i_out[num_bands_out-1] = lambda_max_out;
double dlogl2 = pow(lambda_max_out/lambda_min_out, 1./(num_bands_out-2));
//l_i[0] = lambda_min;
for(int b=2; b<num_bands_out-1; b++) {
l_i_out[b] = l_i_out[b-1] * dlogl2;
cout<<" in NUM_BANDS>2, b = "<<b<<" l_i_out[b] = "<<l_i_out[b]<<endl;
}
for(int b=0; b<num_bands_out; b++) {
l_i12_out[b] = pow( 10., 0.5 * (std::log10(l_i_out[b]) + std::log10(l_i_out[b+1])));
}
}
//
// Assign high and low energy band switches. Those will later decide about the computation of dS and ionization
// Low-energy bands directly input solar radiation into the thermal energy. High-energy bands ionize and are therefore more complicated to treat.
//
num_he_bands = 0;
for(int b=0; b<num_bands_in; b++) {
BAND_IS_HIGHENERGY[b] = 0;
if(photochemistry_level > 0)
if (l_i_in[b + 1] < 0.09116) {
BAND_IS_HIGHENERGY[b] = 1;
num_he_bands++;
}
}
photon_energies = np_somevalue(num_bands_in, 20. * ev_to_K * kb);
for(int b=0; b<num_bands_in; b++) {
photon_energies[b] = 1.24/( l_i_in[b + 1] ) * ev_to_K * kb ;
cout<<"Assigned to highenergy band b = "<<b<<" a photon energy of "<<photon_energies[b]/ev_to_K/kb<<" eV "<<endl;
}
cout<<" WAVELENGTH GRID FINISHED. num_bands_in / num_he_bands / num_bands_out = "<<num_bands_in<<" / "<<num_he_bands<<" / "<<num_bands_out<<endl;
/*
cout<<" ATTENTION: Bands go from "<<l_i[0]<<" till "<<l_i[num_bands]<<", while lmin/lmax was given as "<<lambda_min<<"/"<<lambda_max<<endl;
cout<<" Please confirm this is correct."<<endl;
char tmpchar;
cin>>tmpchar;
*/
if(debug > 0) cout<<"Init: Setup grid memory"<<endl;
//
// Compute cell wall boundaries
// First and last two cells near boundaries are uniform
//
if(type_of_grid==1) {
double dlogx = pow(10.,1./cells_per_decade);
x_i[0] = domain_min / std::pow(dlogx, (num_ghosts-1)) ;
for(int i=1; i<= num_cells; i++) {
x_i[i] = x_i[i-1] * dlogx;
}
//Assign the last boundary as domain maximum as long as nonuniform grid is in the test-phase
domain_max = x_i[num_cells];
cout<<"We have a changed DOMAIN MAX = "<<domain_max<<endl;
}
else if(type_of_grid==2) { //power-law grid with higher log-resolution near the planet
double dlogx = pow(10.,1./cells_per_decade);
double dlogx2 = pow(10.,1./grid2_cells_per_decade);
double templogx = dlogx;
//int grid2_transition_i = 0;
x_i[0] = domain_min / std::pow(dlogx, (num_ghosts-1)) ;
cout<<" grid_transition_i = "<<grid2_transition_i<<endl;
for(int i=1; i<= num_cells; i++) {
if(i <= grid2_transition_i) {
templogx = dlogx;
} else if (i >= (grid2_transition_i + 5)) {
templogx = dlogx2;
} else {
templogx = dlogx + double(i-grid2_transition_i)/5. * (dlogx2 - dlogx);
}
x_i[i] = x_i[i-1] * templogx;
}
//Assign the last boundary as domain maximum as long as nonuniform grid is in the test-phase
//grid2_transition = domain_max;
domain_max = x_i[num_cells];
cout<<"We have a changed DOMAIN MAX = "<<domain_max<<endl;
}
//Uniform grid
else {
x_i[0] = domain_min - dx0*(num_ghosts-1) ;
for(int i=1; i<= num_cells; i++) {
x_i[i] = x_i[i-1] + dx0;
}
}
//
// Differences, surfaces and volumes for all geometries
//
//Differences
for(int i=1; i<num_cells+1; i++) {
dx[i] = x_i[i]-x_i[i-1];
}
// Ghost dxs: valid for linear or log grids
dx[0] = dx[1]*dx[1]/dx[2] ;
dx[num_cells+1] = dx[num_cells]*dx[num_cells]/dx[num_cells-1];
R_core = x_i[1];
// Surface areas
switch (geometry) {
case Geometry::cartesian:
cout<<"Initializing cartesian geometry."<<endl;
for(int i=0; i<num_cells+1; i++) {
surf[i] = 1 ;
}
break;
case Geometry::cylindrical:
cout<<"Initializing cylindrical geometry."<<endl;
for(int i=0; i<num_cells+1; i++) {
surf[i] = 2*M_PI * x_i[i] ;
}
break;
case Geometry::spherical:
cout<<"Initializing spherical geometry."<<endl;
for(int i=0; i<num_cells+1; i++) {
surf[i] = 4*M_PI * x_i[i]*x_i[i] ;
}
break;
}
//Compute shell volumes / voluemtric centres
for(int i=0; i<=num_cells+1; i++) {
double xl, xr ;
if (i < num_cells)
xr = x_i[i];
else
xr = x_i[i-1] + dx[i];
if (i > 0)
xl = x_i[i-1];
else
xl = x_i[0] - dx[0] ;
switch (geometry) {
case Geometry::cartesian:
vol[i] = xr - xl ;
x_iVC[i] = (xr*xr - xl*xl) / (2*vol[i]) ;
break;
case Geometry::cylindrical:
vol[i] = M_PI * (xr*xr - xl*xl);
x_iVC[i] = 2 * M_PI * (xr*xr*xr - xl*xl*xl) / (3*vol[i]) ;
break;
case Geometry::spherical:
vol[i] = (4*M_PI/3) * (xr*xr*xr - xl*xl*xl);
x_iVC[i] = (4*M_PI) * (xr*xr*xr*xr - xl*xl*xl*xl) / (4*vol[i]) ;
break;
}
}
//Compute cell mid positions. Ghost cells also have mid positions in order to balance their pressure gradients
// but need to be calculated after this loop
for(int i=1; i<num_cells+1; i++) {
x_i12[i] = 0.5 * (x_i[i] + x_i[i-1]);
}
//Ghost cells
x_i12[0] = x_i[0] - dx[0]/2 ;
x_i12[num_cells+1] = x_i[num_cells] + dx[num_cells+1]/2;
//
// Grid generation done. Now do a few simple checks on the generated grid values
int all_grid_ok = 1, broken_index;
double broken_value;
for(int i = 0; i <= num_cells+1; i++) {
if( dx[i] < 0 ) {
all_grid_ok = 0;
broken_index = i;
broken_value = dx[i];
}
}
if(debug > 0) cout<<"Init: Finished grid setup"<<endl;
if(!all_grid_ok) {
std::stringstream err ;
err <<"WARNING! Problem with grid values. Example broken value, dx["<<broken_index<<"]="<<broken_value<<endl;
err<<" FIRST AND LAST DX = "<<dx[0]<<" / "<<dx[num_cells+1]<<endl;
throw std::runtime_error(err.str()) ;
}
cout<<endl;
//
//Computing the metric factors for 2nd order non-uniform differentials
//
// Keep in mind that the 0th and num_cells+1 elements are and must stay undefined!
//
for(int i=1; i<num_cells+1; i++) {
omegaminus[i] = 2. * (dx[i-1] + dx[i]) / (dx[i-1] + 2. * dx[i] + dx[i+1]);
omegaplus[i] = 2. * (dx[i+1] + dx[i]) / (dx[i-1] + 2. * dx[i] + dx[i+1]);
}
//Ghost metric factors, those have only to be generated such that hydrostatic eq is preserved, they don't have to be physical
omegaminus[0] = 2*omegaminus[1] - omegaminus[2] ;
omegaplus[0] = 2*omegaplus[1] - omegaplus[2];
omegaminus[num_cells+1] = 2*omegaminus[num_cells] - omegaminus[num_cells-1];
omegaplus[num_cells+1] = 2*omegaplus[num_cells] - omegaplus[num_cells-1];
for(int i=1; i<num_cells+1; i++) {
source_pressure_prefactor_left[i] = (surf[i-1]/vol[i] - 1./dx[i]);
source_pressure_prefactor_right[i] = (surf[i] /vol[i] - 1./dx[i]);
}
if(debug > 0) {
cout<<"DEBUGLEVEL 1: Samples of generated grid values"<<endl;
cout<<"First cell coordinates: |<--"<<x_i[0]<<" // "<<x_i12[0]<<" // "<<x_i[1]<<"-->|"<<endl;
cout<<"Last cell coordinates: |<--"<<x_i[num_cells-1]<<" // "<<x_i12[num_cells-1]<<" // "<<x_i[num_cells]<<"-->|"<<endl;
}
if(debug > 0) cout<<"Init: Setup metric factors"<<endl;
//
//
// Initialize gravity first without any species. Hydrostatic construction needs gravity to start.
//
//
init_grav_pot();
K_zz = np_somevalue(num_cells+2, K_zz_init);
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
////
//
// Create and initialize the species
//
////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
num_species = read_parameter_from_file<int>(filename,"PARI_NUM_SPECIES", debug, 1).value; //Read the number of species
if(num_species<1) {
std::stringstream err;
err<<" Number of species has to be >= 1!"<<endl;
throw std::invalid_argument(err.str()) ;
}
if (NUM_SPECIES != Eigen::Dynamic && num_species != NUM_SPECIES) {
std::stringstream err ;
err << "Error: You compiled aiolos with a different number of species requested"
<< " to that requested in the parameter file.\n You must recompile with either: "
<< " 1) a dynamic number of species (default) or 2) the correct number of species";
throw std::invalid_argument(err.str()) ;
}
init_T_temp = read_parameter_from_file<double>(filename,"INIT_T_TEMP", debug, 1.).value; //Overwrite initial temperature with this value. Use discouraged.
if(debug > 0) cout<<"Init: About to setup species with num_species = "<<num_species<<endl;
species.reserve(num_species);
for(int s = 0; s < num_species; s++) {
species.push_back(c_Species(this, filename, speciesfile, s, debug)); // Here we call the c_Species constructor
}
cout<<endl;
if(use_self_gravity) {
for(int cnt=0; cnt<50; cnt++) {
//cout<<"Before update mass and pot"<<endl;
update_mass_and_pot();
//cout<<"Before second run in update dens"<<endl;
for(int s = 0; s < num_species; s++) {
//species[s].update_kzz_and_gravpot(s);
for(int i=0; i<num_cells+2; i++) {
species[s].phi_s[i] = phi[i];
}
species[s].initialize_hydrostatic_atmosphere(filename);
}
}
}
//Finally, look for the species indices for some important species. Stored in the utility integers e_idx, hnull_idx, hplus_idx etc.
init_highenergy_cooling_indices();
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
////
//
// After successful init, compute all primitive quantities and determine first timestep
//
////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
for(int s = 0; s < num_species; s++)
species[s].compute_pressure(species[s].u);
dt = t_max ; // Old value needed by get_cfl_timestep()
dt = get_cfl_timestep();
if(debug > 0) cout<<"Init: Finished Init. Got initial dt = "<<dt<<" This is only temporary dt_init, not used for the first timestep."<<endl;
//
// Matrix init via Eigen
//
if(debug > 0) cout<<"Init: Setting up friction workspace."<<endl;
alphas_sample = Eigen::VectorXd::Zero(num_cells+2);
friction_sample = Eigen::VectorXd::Zero(num_cells+2);
reaction_matrix = Matrix_t::Zero(num_species, num_species);
reaction_b = Vector_t(num_species);
reaction_matrix_ptr = new Eigen::MatrixXd[omp_get_max_threads()];
reaction_b_ptr = new Eigen::VectorXd[omp_get_max_threads()];
LUchem_ptr = new Eigen::PartialPivLU<Matrix_t>[omp_get_max_threads()];
for(int i =0; i<omp_get_max_threads(); i++ ) {
reaction_matrix_ptr[i] = Matrix_t::Zero(num_species, num_species);
reaction_b_ptr[i] = Vector_t(num_species);
//LUchem_ptr[i] = Eigen::PartialPivLU<Matrix_t>;
}
//n_news = Vector_t(num_species);
for(int s = 0; s < num_species; s++) {
species[s].update_kzz_and_gravpot(s);
}
if(num_species >= 1) {
friction_matrix_T = Matrix_t::Zero(num_species, num_species);
friction_coefficients = Matrix_t::Zero(num_species, num_species);
friction_coeff_mask = Matrix_t::Ones(num_species, num_species);
inv_totmasses = Matrix_t::Zero(num_species, num_species);
resonant_pair_matrix = Matrix_t::Ones(num_species, num_species);
friction_vec_input = Vector_t(num_species);
friction_vec_output = Vector_t(num_species);
friction_dEkin = Vector_t(num_species);
dens_vector = Vector_t(num_species);
numdens_vector = Vector_t(num_species);
mass_vector = Vector_t(num_species);
temperature_vector = Vector_t(num_species);
temperature_vector_augment = Vector_t(num_species);
identity_matrix = Matrix_t::Identity(num_species, num_species);
unity_vector = Vector_t::Ones(num_species);
LU = decltype(LU)(num_species) ;
}
else {
friction_coeff_mask = Matrix_t::Ones(num_species, num_species);
}
//
// Dust species dont feel each other: Punch holes in the coefficient mask for the dust species, so they don't feel each other
// Also set the total inv mass matrix values
//
for(int si=0; si < num_species; si++)
for(int sj=0; sj < num_species; sj++) {
inv_totmasses(si,sj) = 1./(species[si].mass_amu*amu + species[sj].mass_amu*amu);
if(species[si].is_dust_like == 1 && species[sj].is_dust_like == 1) {
friction_coeff_mask(si,sj) = 0.;
friction_coeff_mask(sj,si) = 0.;
}
}
radiation_matrix_T = Matrix_t::Zero(num_species, num_species);
radiation_matrix_M = Matrix_t::Zero(num_species, num_species);
radiation_vec_input = Vector_t(num_species);
radiation_vec_output = Vector_t(num_species);
radiation_cv_vector = Vector_t(num_species);
radiation_T3_vector = Vector_t(num_species);
previous_monitor_J = std::vector<double>(num_bands_out) ;
previous_monitor_T = std::vector<double>(num_species) ;
solar_heating = Eigen::VectorXd::Zero(num_bands_in, 1);
solar_heating_final = Eigen::VectorXd::Zero(num_bands_in, 1);
S_band = Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
dS_band = Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
dS_band_special=Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
dS_band_zero = Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
planck_matrix = Eigen::MatrixXd::Zero(num_plancks, 2);
//
// Compute Planck matrix based on loggrid and 100 K blackbody
//
double sum_planck = 0;
double dsum_planck;
double lmin, lmax;
double dlogx = pow(lmaxglobal/lminglobal, 1./((double)num_plancks));
lT_spacing = dlogx;
//double lT_crit = 14387.770; //=hc/k_b, in units of mum K
double lumi100 = sigma_rad * pow(100.,4.) / pi;
for(int p = 0; p < num_plancks; p++) {
lmin = lminglobal * pow(dlogx,(double)p);
lmax = lmin * dlogx;
dsum_planck = compute_planck_function_integral2(lmin, lmax, 100.) / lumi100;
sum_planck += dsum_planck;
planck_matrix(p,0) = lmax*100.; // Wavelength
planck_matrix(p,1) = sum_planck; // Planck integral until this matrix element
}
if(debug > 0) cout<<"Init: Assigning stellar luminosities 1."<<endl;
for(int s=0; s<num_species; s++) {
species[s].dS = Eigen::VectorXd::Zero(num_cells+2, 1);
species[s].dG = Eigen::VectorXd::Zero(num_cells+2, 1);
species[s].dGdT = Eigen::VectorXd::Zero(num_cells+2, 1);
}
if(debug > 0) cout<<"Init: Assigning stellar luminosities 2."<<endl;
double templumi = 0;
if(true) {
for(int b=0; b<num_bands_in; b++) {
if(debug > 0) cout<<"Init: Assigning stellar luminosities. b ="<<b<<endl;
if(num_bands_in == 1) {
solar_heating(b) = sigma_rad * pow(T_star,4.) * pow(R_star*rsolar,2.)/pow(planet_semimajor*au,2.);
solar_heating(b) += sigma_rad * pow(T_other,4.) * pow(R_other*rsolar,2.)/pow(d_other*au,2.);
solar_heating(b) += UV_star/(4.*pi*pow(planet_semimajor*au,2.));
solar_heating(b) += X_star/(4.*pi*pow(planet_semimajor*au,2.));
templumi += solar_heating(b);
solar_heating_final(b) = solar_heating(b);
cout<<" Solar heating is "<<solar_heating(b)<<" T_star = "<<T_star<<" pow(R_star*rsolar,2.) "<<pow(R_star*rsolar,2.)<<" pow(planet_semimajor*au,2.) "<<planet_semimajor<<endl;
}
else{
cout<<"SOLAR HEATING in bin "<<b;
cout<<" from/to lmin/lmax"<<l_i_in[b];
cout<<"/"<<l_i_in[b+1]<<" with frac = "<<compute_planck_function_integral4(l_i_in[b], l_i_in[b+1], T_star);
solar_heating(b) = sigma_rad * pow(T_star,4.) * pow(R_star*rsolar,2.)/pow(planet_semimajor*au,2.) * compute_planck_function_integral4(l_i_in[b], l_i_in[b+1], T_star);
solar_heating(b) += sigma_rad * pow(T_other,4.) * pow(R_other*rsolar,2.)/pow(d_other*au,2.) * compute_planck_function_integral4(l_i_in[b], l_i_in[b+1], T_other);;
templumi += solar_heating(b);
//if (BAND_IS_HIGHENERGY[b] == 1) {
if(l_i_in[b+1] <= 0.09161) { //Detect the EUV band
if(l_i_in[b+1] <= 0.0161 ) { //Detect the X ray band
solar_heating(b) += X_star/(4.*pi*pow(planet_semimajor*au,2.));
cout<<endl<<" band "<<b<<" detected as X band. Currently, this is treated as thermal band. Assigning X flux "<<X_star/(4.*pi*pow(planet_semimajor*au,2.))<<" based on X lumi "<<X_star;
BAND_IS_HIGHENERGY[b] = 0;
}
else {
solar_heating(b) += UV_star/(4.*pi*pow(planet_semimajor*au,2.));
cout<<endl<<" band "<<b<<" detected as UV band. Assigning UV flux "<<UV_star/(4.*pi*pow(planet_semimajor*au,2.))<<" based on UV lumi "<<UV_star;
}
}
solar_heating_final(b) = solar_heating(b);
}
cout<<" is F = "<<solar_heating(b)<<endl;
}
}
if(fluxfile.compare("---")!=0) {//else {
for(int b = 0; b<num_bands_in; b++) {
double tempenergy = 0.;
int cnt = 0;
double flux;
double lam;
ifstream file(fluxfile);
string line;
if(!file) {
cout<<"Couldnt open flux spectrum file "<<filename<<"!!!!!!!!!!1111"<<endl;
}
while(std::getline( file, line )) {
std::vector<string> stringlist = stringsplit(line," ");
lam = std::stod(stringlist[0]);
flux = std::stod(stringlist[1]);
if(lam > l_i_in[b] && lam < l_i_in[b+1]) {
tempenergy += lam*flux;
cnt++;
}
}
file.close();
if(cnt > 0) {
tempenergy /= (double)cnt;
solar_heating(b) += tempenergy * fluxmultiplier;
templumi += solar_heating(b);
solar_heating_final(b) += solar_heating(b);
} else {
solar_heating(b) = 0.;
}
cout<<"SOLAR HEATING read from file in bin "<<b;
cout<<" from/to lmin/lmax"<<l_i_in[b];
cout<<" is F = "<<solar_heating(b)<<endl;
}
}
cout<<"TOTAL SOLAR HEATING / Flux = "<<templumi<<" Luminosity = "<<(templumi*4.*pi*rsolar*rsolar*pi)<<" | T_irr = "<<pow(templumi/sigma_rad,0.25) <<" T_eq = "<<pow(templumi/sigma_rad/4,0.25) <<" Teq/2**0.25 = "<<pow(templumi/sigma_rad/8,0.25)<<endl;
double totallumi = 0;
double totallumiincr = 0;
for(int b=0; b < num_bands_in; b++) {
totallumiincr = compute_planck_function_integral4(l_i_in[b], l_i_in[b+1], T_star);
totallumi += totallumiincr;
if(debug > 0 ) cout<<" INIT BANDS, b = "<<b<<" l_i_in[b] = "<<l_i_in[b]<<" l_i[b+1] = "<<l_i_in[b+1]<<" l_i12[b] = "<<l_i12_in[b]<<" fraction = "<<totallumiincr<<" fraction for T=1430 K = "<<compute_planck_function_integral3(l_i_in[b], l_i_in[b+1], 1430.)<<endl;
}
cout<<" 2nd Luminosity check, L / sigma T^4/pi is = "<<totallumi/compute_planck_function_integral4(l_i_in[0], l_i_in[num_bands_in-1], T_star)<<endl;
// Initialize the planet's temperature if it has not already been done:
if (T_planet == 0 && use_planetary_temperature) {
T_planet = sigma_rad * (T_int*T_int) * (T_int*T_int) ;
for (int b=0; b < num_bands_in; b++)
T_planet += 0.25*solar_heating(b) ;
T_planet = pow(T_planet/sigma_rad, 0.25) ;
}
total_opacity = Eigen::MatrixXd::Zero(num_cells+2, num_bands_out);
cell_optical_depth = Eigen::MatrixXd::Zero(num_cells+2, num_bands_out);
radial_optical_depth = Eigen::MatrixXd::Zero(num_cells+2, num_bands_out);
total_opacity_twotemp = Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
cell_optical_depth_twotemp = Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
cell_optical_depth_highenergy= Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
radial_optical_depth_twotemp = Eigen::MatrixXd::Zero(num_cells+2, num_bands_in);
highenergy_switch = Eigen::MatrixXd::Ones(num_species, num_bands_in);
Etot_corrected = Eigen::MatrixXd::Zero(num_cells+2, 1);
Jrad_FLD = Eigen::MatrixXd::Zero(num_cells+2, num_bands_out);
Jrad_init = Eigen::MatrixXd::Zero(num_cells+2, num_bands_out);
if(use_rad_fluxes == 1)
tridiag = BlockTriDiagSolver<Eigen::Dynamic>(num_cells+2, num_bands_out + num_species) ;
else if(use_rad_fluxes == 2)
tridiag = BlockTriDiagSolver<Eigen::Dynamic>(num_cells+2, num_bands_out) ;
double rade_l = read_parameter_from_file<double>(filename,"PARI_RADSHOCK_ERL", debug, 1.).value; //Erad_left for radiative shock test
double rade_r = read_parameter_from_file<double>(filename,"PARI_RADSHOCK_ERR", debug, 1.).value; //Erad_right for radiative shock test
init_J_factor = read_parameter_from_file<double>(filename,"INIT_J_FACTOR", debug, -1.).value; //Discontinued
for(int j = 0; j <= num_cells+1; j++) {
if(num_bands_out == 1) {
for(int s = 0; s< num_species; s++){
Jrad_init(j,0) = rad_energy_multiplier * c_light /4. /pi;
if(radiation_matter_equilibrium_test == 0)
Jrad_FLD(j,0) = rad_energy_multiplier * sigma_rad*pow(species[s].prim[j].temperature,4) / pi;
else if(radiation_matter_equilibrium_test == 1)
Jrad_FLD(j,0) = Jrad_init(j,0);
else if(radiation_matter_equilibrium_test == 3)
{
if(j == (num_cells/2+1)) {
Jrad_FLD(j,0) = Jrad_init(j,0);
cout<<" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~RADMATTER TEST 3, I am in cell "<<j<<" and it got J = "<<Jrad_FLD(j,0)<<endl;
}
else
Jrad_FLD(j,0) = 0.;
}
else if(radiation_matter_equilibrium_test >= 4) {//Nonlinear diffusion test, and proper RHD shock tests
double SHOCK_TUBE_MID = read_parameter_from_file<double>(filename,"PARI_INIT_SHOCK_MID", debug, 0.5).value;//Location of discontinuity between left and right values in shock tube
if(x_i12[j] < SHOCK_TUBE_MID)
Jrad_FLD(j,0) = rade_l;
else
Jrad_FLD(j,0) = rade_r;
}
if(debug > 3) {
//if(debug > 1 && j==5) {
cout<<" Jrad("<<j<<","<<0<<") = "<<Jrad_FLD(j,0)<<" dJrad_species["<<s<<"] = "<<rad_energy_multiplier * compute_planck_function_integral3(l_i_out[0], l_i_out[1], species[s].prim[j].temperature)<<" T_rad = "<<pow(pi*Jrad_FLD(j,0)/sigma_rad,0.25)<<" at Tgas = "<<species[s].prim[j].temperature<<endl;
}
}
} else {
for(int b = 0; b < num_bands_out; b++) {
for(int s = 0; s< num_species; s++){
Jrad_FLD(j,b) = rad_energy_multiplier * compute_planck_function_integral3(l_i_out[b], l_i_out[b+1], species[s].prim[j].temperature) * sigma_rad*pow(species[s].prim[j].temperature,4) / pi;
if(Jrad_FLD(j,b) < 1e-50)
Jrad_FLD(j,b) = 1e-50;
Jrad_init(j,b) = Jrad_FLD(j,b);
if(debug > 1 && j==5) {
cout<<" Jrad("<<j<<","<<b<<") = "<<Jrad_FLD(j,b)<<" dJrad_species["<<s<<"] = "<<rad_energy_multiplier * compute_planck_function_integral3(l_i_out[b], l_i_out[b+1], species[s].prim[j].temperature)<<" at T ="<<species[s].prim[j].temperature<<endl;
}
}
}
}
//