11import numpy as np
22import sys
33import os
4- import pickle
5- import itertools
4+ from subprocess import call
65import re
76import ntpath
8- import subprocess
9- from subprocess import call
107
118# Check if we are using python 3
129python_version = sys .version_info [0 ]
1310print ("python_version =" , python_version )
1411
12+
1513class pythonProgramOptions :
1614 """
1715 A class to store and access COMPAS program options in python
@@ -28,55 +26,32 @@ class pythonProgramOptions:
2826 # docker container (src, obj, bin), and the COMPAS executable resides
2927 # in the bin directory (rather than the src directory)
3028 compas_executable_override = os .environ .get ('COMPAS_EXECUTABLE_PATH' )
31-
29+
3230 if (compas_executable_override is None ):
33-
34- # we should fix this one day - we should not assume that the COMPAS executable
35- # is in the 'src' directory. The standard is to put the object files created
36- # by the compile into the 'obj' directory, and the executable files created by
37- # the link in the 'bin' directory.
38- #
39- # for now though, because this is how everybody expects it to be, we'll just check
40- # that the path to the root directory (the parent directory of the directory in
41- # which we expect the executable to reside - for now, 'src') is set to something.
42-
43- compas_root_dir = os .environ .get ('COMPAS_ROOT_DIR' )
44- assert compas_root_dir is not None , "Unable to locate the COMPAS executable: check that the environment variable COMPAS_ROOT_DIR is set correctly, and the COMPAS executable exists."
45-
46- # construct path to executable
47- #
48- # ideally we wouldn't have the 'src' directory name (or any other directory name)
49- # prepended to the executable name - if we just execute the executable name on its
50- # own, as long as the user navigates to the directory in which the executable resides
51- # they don't need to set the COMPAS_ROOT_DIR environment variable
52-
53- compas_executable = os .path .join (compas_root_dir , 'src/COMPAS' )
31+ git_directory = os .environ .get ('COMPAS_ROOT_DIR' )
32+ compas_executable = os .path .join (git_directory , 'src/COMPAS' )
5433 else :
5534 compas_executable = compas_executable_override
5635
57- # check that a file with the correct name exists where we expect it to
58- assert os .path .isfile (compas_executable ), "Unable to locate the COMPAS executable: check that the environment variable COMPAS_ROOT_DIR is set correctly, and the COMPAS executable exists."
59-
60-
6136 enable_warnings = False # option to enable/disable warning messages
6237
63- number_of_systems = int ( 1e2 ) # number of systems per batch
38+ number_of_systems = 10 # number of systems per batch
6439
6540 populationPrinting = False
6641
6742 randomSeedFileName = 'randomSeed.txt'
6843 if os .path .isfile (randomSeedFileName ):
6944 random_seed = int (np .loadtxt (randomSeedFileName ))
7045 else :
71- random_seed = 0 # If you want a random seed, use: np.random.randint(2,2**63-1)
46+ random_seed = 0 # If you want a random seed, use: np.random.randint(2,2**63-1)
7247
7348 # environment variable COMPAS_LOGS_OUTPUT_DIR_PATH is used primarily for docker runs
7449 # if COMPAS_LOGS_OUTPUT_DIR_PATH is set (!= None) it is used as the value for the
7550 # --output-path option
7651 # if COMPAS_LOGS_OUTPUT_DIR_PATH is not set (== None) the current working directory
7752 # is used as the value for the --output-path option
7853 compas_logs_output_override = os .environ .get ('COMPAS_LOGS_OUTPUT_DIR_PATH' )
79-
54+
8055 if (compas_logs_output_override is None ):
8156 output = os .getcwd ()
8257 output_container = None # names the directory to be created and in which log files are created. Default in COMPAS is "COMPAS_Output"
@@ -90,7 +65,7 @@ class pythonProgramOptions:
9065 # if COMPAS_INPUT_DIR_PATH is not set (== None) the current working directory
9166 # is prepended to input filenames
9267 compas_input_path_override = os .environ .get ('COMPAS_INPUT_DIR_PATH' )
93-
68+
9469 #-- option to make a grid of hyperparameter values at which to produce populations.
9570 #-- If this is set to true, it will divide the number_of_binaries parameter equally
9671 #-- amoungst the grid points (as closely as possible). See the hyperparameterGrid method below
@@ -100,9 +75,6 @@ class pythonProgramOptions:
10075 hyperparameterList = False
10176 shareSeeds = False
10277
103- notes_hdrs = None # no annotations header strings (no annotations)
104- notes = None # no annotations
105-
10678 mode = 'BSE' # evolving single stars (SSE) or binaries (BSE)?
10779
10880 grid_filename = None # grid file name (e.g. 'mygrid.txt')
@@ -118,11 +90,11 @@ class pythonProgramOptions:
11890 else :
11991 grid_filename = compas_input_path_override + '/' + grid_filename .strip ("'\" " )
12092
121- logfile_definitions = "COMPAS_Output_Definitions.txt" # logfile record definitions file name (e.g. 'logdefs.txt')
93+ logfile_definitions = None # logfile record definitions file name (e.g. 'logdefs.txt')
12294
12395 if logfile_definitions != None :
12496 # if the grid filename supplied is already fully-qualified, leave it as is
125- head , tail = ntpath .split (logfile_definitions ) # split into pathname and base filename
97+ head , tail = ntpath .split (grid_filename ) # split into pathname and base filename
12698
12799 if head == '' or head == '.' : # no path (or CWD) - add path as required
128100 logfile_definitions = tail or ntpath .basename (head )
@@ -156,6 +128,8 @@ class pythonProgramOptions:
156128
157129 chemically_homogeneous_evolution = 'PESSIMISTIC' # chemically homogeneous evolution. Options are 'NONE', 'OPTIMISTIC' and 'PESSIMISTIC'
158130
131+ store_input_files = True # store input files in output container?
132+
159133 switch_log = False
160134
161135 common_envelope_alpha = 1.0
@@ -167,24 +141,22 @@ class pythonProgramOptions:
167141 common_envelope_maximum_donor_mass_revised_energy_formalism = 2.0
168142 common_envelope_recombination_energy_density = 1.5E13
169143 common_envelope_alpha_thermal = 1.0 # lambda = alpha_th*lambda_b + (1-alpha_th)*lambda_g
170- common_envelope_lambda_multiplier = 1.0 # Multiply common envelope lambda by some constant
171- common_envelope_allow_main_sequence_survive = True # Allow main sequence stars to survive CE. Was previously False by default
144+ wolf_rayet_multiplier = 1.0
145+ cool_wind_mass_loss_multiplier = 1.0
172146 common_envelope_mass_accretion_prescription = 'ZERO'
173147 common_envelope_mass_accretion_min = 0.04 # For 'MACLEOD+2014' [Msol]
174148 common_envelope_mass_accretion_max = 0.10 # For 'MACLEOD+2014' [Msol]
175149 envelope_state_prescription = 'LEGACY'
176- common_envelope_allow_radiative_envelope_surive = False
177- common_envelope_allow_immediate_RLOF_post_CE_survive = False
178150
179151 mass_loss_prescription = 'VINK'
180- luminous_blue_variable_prescription = 'HURLEY_ADD'
152+ luminous_blue_variable_prescription = 'BELCZYNSKI' #' HURLEY_ADD'
181153 luminous_blue_variable_multiplier = 1.5
182154 overall_wind_mass_loss_multiplier = 1.0
183155 wolf_rayet_multiplier = 1.0
184156 cool_wind_mass_loss_multiplier = 1.0
185157 check_photon_tiring_limit = False
186158
187- circularise_binary_during_mass_transfer = False
159+ circularise_binary_during_mass_transfer = True
188160 angular_momentum_conservation_during_circularisation = False
189161 mass_transfer_angular_momentum_loss_prescription = 'ISOTROPIC'
190162 mass_transfer_accretion_efficiency_prescription = 'THERMAL'
@@ -204,7 +176,7 @@ class pythonProgramOptions:
204176 timestep_multiplier = 1.0 # Optional multiplier relative to default time step duration
205177
206178 initial_mass_function = 'KROUPA'
207- initial_mass_min = 10 .0 # Use 1.0 for LRNe, 5.0 for DCOs [Msol]
179+ initial_mass_min = 5 .0 # Use 1.0 for LRNe, 5.0 for DCOs [Msol]
208180 initial_mass_max = 150.0 # Stellar tracks extrapolated above 50 Msol (Hurley+2000) [Msol]
209181
210182 initial_mass_power = 0.0
@@ -251,7 +223,7 @@ class pythonProgramOptions:
251223
252224 neutrino_mass_loss_BH_formation = "FIXED_MASS" # "FIXED_FRACTION"
253225 neutrino_mass_loss_BH_formation_value = 0.1 # Either fraction or mass (Msol) to lose
254-
226+
255227 remnant_mass_prescription = 'FRYER2012' #
256228 fryer_supernova_engine = 'DELAYED'
257229 black_hole_kicks = 'FALLBACK'
@@ -294,12 +266,10 @@ class pythonProgramOptions:
294266 PPI_lower_limit = 35.0 # Minimum core mass for PPI [Msol]
295267 PPI_upper_limit = 60.0 # Maximum core mass for PPI [Msol]
296268
297- pulsational_pair_instability_prescription = 'FARMER '
269+ pulsational_pair_instability_prescription = 'MARCHANT '
298270
299271 maximum_neutron_star_mass = 2.5 # [Msol]
300272
301- add_options_to_sysparms = 'GRID' # should all option values be added to system parameters files? options are 'ALWAYS', 'GRID', and 'NEVER'
302-
303273 log_level = 0
304274 log_classes = []
305275
@@ -342,7 +312,6 @@ class pythonProgramOptions:
342312 debug_to_file = False
343313 errors_to_file = False
344314
345-
346315 def booleanChoices (self ):
347316 booleanChoices = [
348317 self .enable_warnings ,
@@ -358,13 +327,12 @@ def booleanChoices(self):
358327 self .pulsation_pair_instability ,
359328 self .quiet ,
360329 self .common_envelope_allow_main_sequence_survive ,
361- self .common_envelope_allow_radiative_envelope_surive ,
362- self .common_envelope_allow_immediate_RLOF_post_CE_survive ,
363330 self .evolvePulsars ,
364331 self .debug_to_file ,
365332 self .errors_to_file ,
366333 self .allow_rlof_at_birth ,
367334 self .allow_touching_at_birth ,
335+ self .store_input_files ,
368336 self .switch_log ,
369337 self .check_photon_tiring_limit
370338 ]
@@ -386,13 +354,12 @@ def booleanCommands(self):
386354 '--pulsational-pair-instability' ,
387355 '--quiet' ,
388356 '--common-envelope-allow-main-sequence-survive' ,
389- '--common-envelope-allow-radiative-envelope-surive' ,
390- '--common-envelope-allow-immediate-rlof-post-ce-survive' ,
391357 '--evolve-pulsars' ,
392358 '--debug-to-file' ,
393359 '--errors-to-file' ,
394360 '--allow-rlof-at-birth' ,
395361 '--allow-touching-at-birth' ,
362+ '--store-input-files' ,
396363 '--switch-log' ,
397364 '--check-photon-tiring-limit'
398365 ]
@@ -583,8 +550,6 @@ def numericalCommands(self):
583550
584551 def stringChoices (self ):
585552 stringChoices = [
586- self .notes_hdrs ,
587- self .notes ,
588553 self .mode ,
589554 self .case_BB_stability_prescription ,
590555 self .chemically_homogeneous_evolution ,
@@ -628,16 +593,13 @@ def stringChoices(self):
628593 self .logfile_supernovae ,
629594 self .logfile_switch_log ,
630595 self .logfile_system_parameters ,
631- self .neutrino_mass_loss_BH_formation ,
632- self .add_options_to_sysparms
596+ self .neutrino_mass_loss_BH_formation
633597 ]
634598
635599 return stringChoices
636600
637601 def stringCommands (self ):
638602 stringCommands = [
639- '--notes-hdrs' ,
640- '--notes' ,
641603 '--mode' ,
642604 '--case-BB-stability-prescription' ,
643605 '--chemically-homogeneous-evolution' ,
@@ -681,8 +643,7 @@ def stringCommands(self):
681643 '--logfile-supernovae' ,
682644 '--logfile-switch-log' ,
683645 '--logfile-system-parameters' ,
684- '--neutrino-mass-loss-BH-formation' ,
685- '--add-options-to-sysparms'
646+ '--neutrino-mass-loss-BH-formation'
686647 ]
687648
688649 return stringCommands
@@ -711,12 +672,12 @@ def generateCommandLineOptionsDict(self):
711672 and run directly as a terminal command, or passed to the stroopwafel interface
712673 where some of them may be overwritten. Options not to be included in the command
713674 line should be set to pythons None (except booleans, which should be set to False)
714-
675+
715676 Parameters
716677 -----------
717678 self : pythonProgramOptions
718679 Contains program options
719-
680+
720681 Returns
721682 --------
722683 commands : str or list of strs
@@ -725,17 +686,17 @@ def generateCommandLineOptionsDict(self):
725686 booleanCommands = self .booleanCommands ()
726687 nBoolean = len (booleanChoices )
727688 assert len (booleanCommands ) == nBoolean
728-
689+
729690 numericalChoices = self .numericalChoices ()
730691 numericalCommands = self .numericalCommands ()
731692 nNumerical = len (numericalChoices )
732693 assert len (numericalCommands ) == nNumerical
733-
694+
734695 stringChoices = self .stringChoices ()
735696 stringCommands = self .stringCommands ()
736697 nString = len (stringChoices )
737698 assert len (stringCommands ) == nString
738-
699+
739700 listChoices = self .listChoices ()
740701 listCommands = self .listCommands ()
741702 nList = len (listChoices )
@@ -745,25 +706,25 @@ def generateCommandLineOptionsDict(self):
745706 ### Collect all options into a dictionary mapping option name to option value
746707
747708 command = {'compas_executable' : self .compas_executable }
748-
709+
749710 for i in range (nBoolean ):
750711 if booleanChoices [i ] == True :
751712 command .update ({booleanCommands [i ] : '' })
752713 elif booleanChoices [i ] == False :
753714 command .update ({booleanCommands [i ] : 'False' })
754-
715+
755716 for i in range (nNumerical ):
756717 if not numericalChoices [i ] == None :
757718 command .update ({numericalCommands [i ] : str (numericalChoices [i ])})
758-
719+
759720 for i in range (nString ):
760721 if not stringChoices [i ] == None :
761722 command .update ({stringCommands [i ] : cleanStringParameter (stringChoices [i ])})
762-
723+
763724 for i in range (nList ):
764725 if listChoices [i ]:
765726 command .update ({listCommands [i ] : ' ' .join (map (str ,listChoices [i ]))})
766-
727+
767728 return command
768729
769730
@@ -775,7 +736,7 @@ def combineCommandLineOptionsDictIntoShellCommand(commandOptions):
775736 """
776737
777738 shellCommand = commandOptions ['compas_executable' ]
778- del commandOptions ['compas_executable' ]
739+ del commandOptions ['compas_executable' ]
779740 for key , val in commandOptions .items ():
780741 shellCommand += ' ' + key + ' ' + val
781742
0 commit comments