def get_values(self): this = 'Read values from file (F) or calculate from equation (E): ' user_input = 'risimif' while not af.correct_user_input(user_input, ['f', 'e']): user_input = input(this) if user_input.lower() == 'f': this = '\nATTENTION: What is usually assumed regarding the structure ' that = 'of the data in the file is assumed here, too! (First line is ' siht = 'table header, columns separated by tabs).\n' print(this + that + siht) this = 'Full path of folder with activation energy file: ' that = 'Name of file (incl. extension): ' self.path = af.get_path(this + that) self.infile = af.get_infile(self.path) self._generate_values_from_file() elif user_input.lower() == 'e': # A function can be parametrized differently for different areas of # conversion. To be able to handle that, I need to know the number # of different functions. self.number_of_functions = af.get_user_input('number_of_functions') print('') self._generate_values_from_function() self._delete_duplicates()
def main(): print("""\n\nStep separation\n This program separates all steps in DSC-files from each other and returns as many files as there are steps. ATTENTION: IT IS ASSUMED THAT THE COLUMNS ARE SEPARATED WITH TABS! ATTENTION: It is assumed that the keyword < [step] > is followed by three text-lines which contain the following (in this order): line 1.: name of the step line 2.: table header -> variables line 3.: table header -> units ATTENTION: This probably works just with files exported from the TA Instruments TRIOS software. Other vendors probably structure their files differently. """) path = af.get_path() infile = af.get_infile(path) all_data, steps, table_header = extract_data(infile) outfiles = create_filenames(path, steps) for i in range(len(outfiles)): write_step_data_into_file(outfiles[i], table_header, all_data[i]) move_to_new_directory(path, infile, outfiles)
def main(): print("""\n\nCalculating the total heat of reaction.\n ATTENTION: It is assumed that the input-file ran through the "step_separator"-program. Thus the first line in the files is the table header and from the second line follows he data and NOTING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: It is assumed that the data is post-cure run subtracted (if this applies). ATTENTION: It is assumed that the input file is baseline corrected (meaning: steady state has a mean heat flow value of zero) ATTENTION: The returned value will be in Joule per GRAM! ATTENTION: This is really just a simple addition of data. """) path = af.get_path() infile = af.get_infile(path) timestep = af.get_user_input('timestep') data = cd.Data(timestep, infile) data.calculate_total_heat_of_reaction() print('') this = "The total heat of reaction is {} J/g.\n".format(data.total_heat) print(this)
def main(): print("""\n\nSubtracting the post cure run from the cure run.\n ATTENTION: It is assumed that cure and post-cure data are in separate files. ATTENTION: It is assumed that these two files are in the same folder. ATTENTION: It is assumed that these files ran through the "step_separator"-program. Thus the first line in the files is the table header and from the second line follows the data and NOTHING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: This is really just a simple subraction of data, line for line. ATTENTION: It is assumed that cure and post-cure run are identical in time steps and temperature for each time step (but not the heat flow (or heat capacity) of course). Meaning 1: The resulting file will contain time-steps and temperature (and heat capacity if it applies) from the cure run! Meaning 2: If the length of the steps is not identical this program will return bogus! ATTENTION: The time between two measurements is to be given in SECONDS. The new file will have this time step in between the measurements. So the time in the new file will be in SECONDS! Not minutes as it may be the case with the original file. ATTENTION: Heat Flow: It is assumed that the NORMALIZED Heat Flow is present in the raw-data. Not normalized heat flows will be ignored. Heat Capacity: The heat capacity from the CURE-run will be used. Again, just the NORMALIZED heat capacity will be used. """) path = af.get_path() text = 'Name of CURE-run file (incl. extension): ' cure_file = af.get_infile(path, text) text = 'Name of POST-cure-run file (incl. extension): ' post_file = af.get_infile(path, text) outfile_name = af.get_user_input('outfile') timestep = af.get_user_input('timestep') cure_data = cd.Data(timestep, cure_file) post_data = cd.Data(timestep, post_file) print("Subtracting ...") new_data = subtracted_data(cure_data, post_data, timestep) # subtracted_data() has a return condition that does not do anything # if the data does not contain heat flow data. if new_data: order_of_variables = create_table_header(new_data) outfile = path + outfile_name print("Writing to file ...\n") af.write_to_file(outfile, new_data, order_of_variables) print( 'A new file called < {} > was created in the same folder.'.format( outfile_name))
def main(): print("""\n\nCalculate conversion and write to file.\n ATTENTION: It is assumed that the files ran through the "step_separator"-program. Thus the first line in the file is the table header and from the second line follows he data and NOTING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: It is assumed that the data is post-cure and baseline corrected. The program does NOT check for this! If this is not the case the program will run anyway and return bogus! However, it is NOT necessar that the sample reached full cure, if a value for the total heat of reaction is provided. ATTENTION: The time between two measurements is to be given in SECONDS. The new file will have this time step in between the measurements. So the time in the new file will be in SECONDS! Not minutes as it may be the case with the original file. ATTENTION: Heat Flow: It is assumed that the NORMALIZED Heat Flow is present in the raw-data. Not normalized heat flows will be ignored. Heat Capacity: Just the NORMALIZED heat capacity will be printed into the to the new file! """) path = af.get_path() infile = af.get_infile(path) outfile_name = af.get_user_input('outfile') timestep = af.get_user_input('timestep') total_heat = af.get_user_input('total_heat', True, 'float') initial_conversion = af.get_user_input('initial_conversion', True, 'float') new_data = cd.Data(timestep, infile) print("Calculating the conversion ...") new_data.calculate_conversion(total_heat, initial_conversion) order_of_variables = create_table_header(new_data) outfile = path + outfile_name print("Writing to file ...\n") af.write_to_file(outfile, new_data, order_of_variables) print('A new file called < {} > was created in the same folder.'.format( outfile_name))
def main(): print("""\n\nStitching several steps together into one file\n ATTENTION: It is assumed that the steps are separate files. ATTENTION: It is assumed that these files are in the same folder. ATTENTION: It is assumed that these files ran through the "step_separator"-program. Thus the first line in the files is the table header and from the second line follows he data and NOTING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: This is really just a simple putting the data of one step behind the other, line for line. ATTENTION: It is assumed that step one actually is followed by step two is followed by step three etc. ATTENTION: It is assumed that all files have the same time step between measurements ATTENTION: It is assumed that step one actually is followed by step two is followed by step three etc. THIS WILL NOT BE CHECKED! ATTENTION: The time between two measurements is to be given in SECONDS. The new file will have this time step in between the measurements. So the time in the new file will be in SECONDS! Not minutes as it may be the case with the original file. ATTENTION: Heat Flow: It is assumed that the NORMALIZED Heat Flow is present in the raw-data. Not normalized heat flows will be ignored. Heat Capacity: If heat capacity data is present just the NORMALIZED heat capacity will be used. """) path = af.get_path() # Since I want to loop until all filenames are provided I can not all_filenames = [] i = 1 loop = True while loop: this = 'Name of file #{} (incl. extension) -- '.format(i) that = 'press just ENTER to continue to next step: ' text = this + that infile = af.get_infile(path, text, True) # af.get_infile() returns True if I allow a blank input. if infile == True and i > 2: loop = False elif infile == True: print("I won't stop asking before more than one filename is provided.") else: all_filenames.append(infile) i += 1 outfile_name = outfile_name = af.get_user_input('outfile') timestep = af.get_user_input('timestep') all_data = [] for infile in all_filenames: data = cd.Data(timestep, infile) all_data.append(data) print('') print("Stitching ...") new_data = stitched_together(all_data, timestep) print('') order_of_variables = create_table_header(new_data) outfile = path + outfile_name print("Writing to file ...\n") af.write_to_file(outfile, new_data, order_of_variables) print('A new file called < {} > was created in the same folder.'.format(outfile_name))
def main(): print("""\n\nCorrecting the baseline to zero\n ATTENTION: It is assumed that the file ran through the "step_separator"-program. Thus the first line in the files is the table header and from the second line follows he data and NOTING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: This is really just the simple subtraction of a value from the heat flow data. ATTENTION: The time between two measurements is to be given in SECONDS. The new file will have this time step in between the measurements. So the time in the new file will be in SECONDS! Not minutes as it may be the case with the original file. ATTENTION: Heat Flow: It is assumed that the NORMALIZED Heat Flow is present in the raw-data. Not normalized heat flows will be ignored. If no normalized heat flow data is available the program will crash Heat Capacity: If heat capacity data is present just the NORMALIZED heat capacity will be used. """) path = af.get_path() infile = af.get_infile(path) outfile_name = af.get_user_input('outfile') timestep = af.get_user_input('timestep') this = 'Steady state (normalized) heat flow ' that = '(leave EMPTY if it shall be calculated from the data itself): ' text = this + that steady_state_heat_flow = af.get_user_input(text, True, 'float') intervall = None if steady_state_heat_flow == None: this = 'Intervall (in SECONDS) over which the steady (normalized) heat ' that = 'flow shall be calculated (leave EMPTY to use 5 minutes 23 ' siht = 'seconds = 323 seconds): ' text = this + that + siht intervall = af.get_user_input(text, True, 'float') # I always call the data "new_data", thus I keep this here, even though it # would not be necessary! new_data = cd.Data(timestep, infile) print('') print('Correcting the baseline ...') new_data.correct_baseline(steady_state_heat_flow, intervall) # If the steady state heat flow can NOT be calculated # data._calculate_steady_state_heat_flow() writes a note to the user and # returns False and subsequently data.correct_baseline sets # data.baseline_corrected to False and returns False. # Don't continue if this happens. if not new_data.baseline_corrected: return print('') order_of_variables = create_table_header(new_data) outfile = path + outfile_name print("Writing to file ...\n") af.write_to_file(outfile, new_data, order_of_variables) print('A new file called < {} > was created in the same folder.'.format( outfile_name))
def main(): print("""\n\nCalculating the actual kinetic function.\n ATTENTION: It is assumed that the input-files ran through the "step_separator"-program. Thus the first line in the files is the table header and from the second line follows he data and NOTING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: The temperature will be converted to KELVIN! ATTENTION: It is assumed that the input file is baseline corrected (meaning: baseline has a mean heat flow value of zero). ATTENTION: It is assumed that the data is post-cure run subtracted (if this applies). ATTENTION: It is assumed that folder contains just files with the relevant data! And (if it applies) the file with the conversion dependent activation energy. """) # Get the location of the raw files. this = 'Full path of folder with files (ATTENTION: folder shall contain ' that = 'JUST these files!): ' path = af.get_path(this + that) timestep = af.get_user_input('timestep') in_kelvin = af.get_user_input('kelvin') total_heat = af.get_user_input('total_heat', True, 'float') initial_conversion = af.get_user_input('initial_conversion', True, 'float') text = 'Compensation parameter a = ' # Don't use dec()-numbers here, because these values are needed shortly # after in numpy functions. a = float(af.get_user_input(text)) text = 'Compensation parameter b = ' b = float(af.get_user_input(text)) conversion_step = af.get_user_input('conversion_step') print('\nRegarding the activation energy:') activation_energy = cd.UserFunction(conversion_step, timestep) # I want the pre-factors also to be a UserFunctionobject. But the __init__ # of class UserFunction() can not handle to calculate the values from given # third values (not the conversion). I could write that, but it doesn't # seem worth it. Thus I simply deepcopy activation_energy, calculate # the pre-factor values with calculate_pre_factor() and simply replace # the value-attribute with the new list. pre_factors = deepcopy(activation_energy) new_values = calculate_pre_factor(a, b, activation_energy) pre_factors.values = new_values print() # That the user does NOT need to delete all the time the file this # program creates these are taken out from the list with the filenames # in the folder. This is the reason why the outfile_name(s) are hard coded. # Over many runs it turned out that this is a good thing to do. filenames = [x for x in os.listdir(path) if ('0000_calculated' not in x.lower() and \ '0001_calculated' not in x.lower()) and \ '00000_activation' not in x.lower() and \ '00000_compensation' not in x.lower() and \ '000_actual_kinetic_function' not in x.lower()] print('') for filename in filenames: print("\nWorking on {} ...".format(filename)) data = cd.Data(timestep, path + filename) data.in_kelvin = in_kelvin if not in_kelvin: print("Setting temperature to Kelvin ...") # create_temperature_in_kelvin() will be called even if the temperature # is already in Kelvin, because it contains a check if the data # actually has temperature data. This is just a check, which is probably # not necessary. data.create_temperature_in_kelvin() if not total_heat: print("Calculating total heat of reaction ...") data.calculate_total_heat_of_reaction() else: data.total_heat = deepcopy(total_heat) print("Calculating the conversion ...") data.calculate_conversion(total_heat, initial_conversion) # I need of course just the heat flow values for the given conversion # steps. data.heat_flow = data._get_correct_values_from_file(activation_energy.conversion, \ data.conversion, data.heat_flow) # Dito for the temperature. data.temperature = data._get_correct_values_from_file(activation_energy.conversion, \ data.conversion, data.temperature) # And finally just the necessary conversion steps. data.conversion = activation_energy.conversion data.activation_energy = activation_energy.values data.pre_factor = pre_factors.values # This is what I'm here for. calculate_kinetic_function(data) outfile_name = '000_actual_kinetic_function_{}'.format(filename) #print("Writing calculated values to a file ...") outfile = path + outfile_name order_of_variables = create_table_header(data) af.write_to_file(outfile, data, order_of_variables) print() this = 'Many new files were created in the stated folder containing the ' that = 'actual kinetic function for each raw-data file.\n' print(this + that)
def main(): print("""\n\nCalculating the compensation parameters.\n ATTENTION: It is assumed that the input-files ran through the "step_separator"-program. Thus the first line in the files is the table header and from the second line follows he data and NOTING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: The temperature will be converted to KELVIN! ATTENTION: It is assumed that the input file is baseline corrected (meaning: baseline has a mean heat flow value of zero). ATTENTION: It is assumed that the data is post-cure run subtracted (if this applies). ATTENTION: It is assumed that folder contains just files with the relevant data! That means just data from dynamic experiments ATTENTION: Fitting will take place between 20 percent and 80 percent. It is assumed that the data actually reaches 80 percent conversion. ATTENTION: For each input file a file with the calculated parameters and a second file with the calculated functions will be created. Of interest is probably just the file < 00000_compensation_parameters > in which the mean value of all compensation parameters is reported. """) # Get the location of the raw files. this = 'Full path of folder with files (ATTENTION: folder shall contain ' that = 'JUST these files!): ' path = af.get_path(this + that) timestep = af.get_user_input('timestep') in_kelvin = af.get_user_input('kelvin') total_heat = af.get_user_input('total_heat', True, 'float') initial_conversion = af.get_user_input('initial_conversion', True, 'float') # That the user does NOT need to delete all the time the file this # program creates these are taken out from the list with the filenames # in the folder. This is the reason why the outfile_name(s) are hard coded. # Over many runs it turned out that this is a good thing to do. filenames = [x for x in os.listdir(path) if ('0000_calculated' not in x.lower() and \ '0001_calculated' not in x.lower()) and \ '00000_activation' not in x.lower() and \ '00000_compensation' not in x.lower()] print('') all_compensation_parameters = {} all_a = [] all_b = [] for filename in filenames: print("Working on {} ...".format(filename)) data = cd.Data(timestep, path + filename) data.in_kelvin = in_kelvin if not in_kelvin: print("Setting temperature to Kelvin ...") # create_temperature_in_kelvin() will be called even if the temperature # is already in Kelvin, because it contains a check if the data # actually has temperature data. This is just a check, which is probably # not necessary. data.create_temperature_in_kelvin() if not total_heat: print("Calculating total heat of reaction ...") data.calculate_total_heat_of_reaction() else: data.total_heat = deepcopy(total_heat) print("Calculating the conversion ...") data.calculate_conversion(total_heat, initial_conversion) print("Calculating the kinetic model values ...") data.calculate_left_hand_side() print("Fitting ...") data.fit_all_for_compensation_parameters() all_a.append(data.a) all_b.append(data.b) all_compensation_parameters.update( {filename: { 'a': data.a, 'b': data.b }}) print("Writing calculated values to a file ...") outfile_name = '0000_calculated_function_values_{}'.format(filename) outfile = path + outfile_name order_of_variables = create_table_header(data) af.write_to_file(outfile, data, order_of_variables) outfile_name = '0001_calculated_fitting_parameters_{}'.format(filename) outfile = path + outfile_name write_linear_fitting_parameters(outfile, data, 'per_model') print() a_mean = sum(all_a) / len(all_a) b_mean = sum(all_b) / len(all_b) all_compensation_parameters.update({'a_mean': a_mean, 'b_mean': b_mean}) print('\nmean a: {} J/mol, mean b: {}\n'.format(a_mean, b_mean)) outfile_name = '00000_compensation_parameters.txt' outfile = path + outfile_name write_linear_fitting_parameters(outfile, all_compensation_parameters, 'mean') print() this = 'Many new files were created in the stated folder.' that = 'Of highest interest is probably < {} >.\n'.format(outfile_name) print(this + that)
def main(): print("""\n\nPredicting DSC heat flow curves.\n Important: Use the exact (!) parameters for a given dataset -- total heat, compensation parameters (if it is a dynamic measurement), parameters of the kinetic function -- if you want to compare the measured DSC heat flow curves with predicted values. This may be seen as a measure how good the method is in figuring out the kinetic parameters from a given set of data. Use mean values for all these parameters, to make a more general prediction. ATTENTION: This program can EITHER predict isothermal heat flow OR the heat flow if a linear (!) temperature ramp is applied. If a general temperature program shall be predicted the program has to be called again, with changed parameters. E.g. a ramp followed by an isothermal would first simulate the ramp, starting with conversion = 0.0 and having at the end a conversion of 23 percent (for example). Afterwards, a second call of this program predicts the isothermal, taking the 23 percent as initial degree of cure. ATTENTION: This program assumes that all heat is transported away at once. This is just valid for small samples. The behaviour of large samples, which heat up during the curing process, can NOT be predicted with this simple tool! """) path = af.get_path('Folder where the result shall be stored: ') outfile_name = af.get_user_input('outfile') this = '\nATTENTION: small time increments and long overall timeframes will ' that = 'take quite some time to calculate!\n' print(this + that) timestep = af.get_user_input('timestep') text = 'After how many SECONDS shall the calculation latest stop? ' timeframe = af.get_user_input(text) isothermal = af.get_user_input('prediction_mode') if not isothermal: text = 'Start temperature in KELVIN: ' start_temperature = af.get_user_input(text) end_temperature = af.get_user_input('End temperature in KELVIN: ') # I use here as the only place minutes as time, because the ramps # in typical DSC instruments are given in Kelvin per minute. text = 'Temperature ramp in Kelvin per MINUTE: ' # The above is just for te convenience of the user. In the end I need # this value of course in seconds. ramp = af.get_user_input(text) / dec('60.0') else: text = 'Isothermal temperature in KELVIN: ' start_temperature = af.get_user_input(text) end_temperature = start_temperature ramp = dec('0.0') # Here the total heat needs to be stated by the user since there is # nothing where it could be calculated from like in all the other cases # where rawdata is provided. text = 'Total heat of reaction (J/g): ' total_heat = af.get_user_input(text) initial_conversion = af.get_user_input('initial_conversion', True, 'float') # Some (kinetic) functions may not work properly if the conversion is zero. # So even if it is zero I have to start with a small value. if initial_conversion == None: initial_conversion = dec('0.0000001') conversion_step = af.get_user_input('conversion_step') # With the above all is ready to finally create the Prediction() object. # All else will be added manually below. prediction = cd.Prediction(timestep, timeframe, isothermal, \ start_temperature, end_temperature, ramp, total_heat, \ initial_conversion) print('\nRegarding the activation energy:') activation_energy = cd.UserFunction(conversion_step, timestep) prediction.activation_energy = activation_energy text = 'Compensation parameter a = ' # Don't use dec()-numbers here, because these values are needed shortly # after in numpy functions. a = float(af.get_user_input(text)) text = 'Compensation parameter b = ' b = float(af.get_user_input(text)) # I want the pre-factors also to be a UserFunctionobject. But the __init__ # of class UserFunction() can not handle to calculate the values from given # third values (which are not the conversion). I could write that, but it # doesn't seem worth it. Thus I simply deepcopy activation_energy, calculate # the pre-factor values with calculate_pre_factor() and simply replace # the value-attribute with the new list. pre_factor = deepcopy(activation_energy) new_values = kfc.calculate_pre_factor(a, b, activation_energy) pre_factor.values = new_values prediction.pre_factor = pre_factor print('\n\nRegarding the kinetic function:') kinetic_function = cd.UserFunction(conversion_step, timestep) prediction.kinetic_function = kinetic_function # And finally the thing is happening what I actually wanted to happen. # Hey look! It's a one liner ;) prediction.predict() order_of_variables = create_table_header(prediction) outfile = path + outfile_name print('\nWriting to File ...') af.write_to_file(outfile, prediction, order_of_variables) print('') this = 'The < {} > file with the predicted values was '.format(outfile_name) that = 'created in the stated folder.\n' print(this + that)
def main(): print("""\n\nCalculating the conversion dependent activation energy.\n ATTENTION: It is assumed that the input-files ran through the "step_separator"-program. Thus the first line in the files is the table header and from the second line follows he data and NOTING else. ATTENTION: It is assumed that tabs separate the columns. ATTENTION: The temperature will be converted to KELVIN! ATTENTION: This program will work JUST over time, NOT over temperature. It should be the same though! ATTENTION: The normalzided heat flow data will be used. ATTENTION: It is assumed that the input file is baseline corrected (meaning: baseline has a mean heat flow value of zero). ATTENTION: It is assumed that the data is post-cure run subtracted (if this applies). ATTENTION: It is assumed that folder contains just files with the relevant data! E.g. just the isothermal data from several experiments at different temperatures. """) # Get the location of the raw files. this = 'Full path of folder with files (ATTENTION: folder shall contain ' that = 'JUST these files!): ' path = af.get_path(this + that) timestep = af.get_user_input('timestep') in_kelvin = af.get_user_input('kelvin') total_heat = af.get_user_input('total_heat', True, 'float') initial_conversion = af.get_user_input('initial_conversion', True, 'float') conversion_step = af.get_user_input('conversion_step') text = 'Initial guess for the activation energy in J/mol: ' initial_guess = af.get_user_input(text) # Yes, this is a hard coded filename. outfile_name = '00000_Activation_energies.txt' outfile = path + outfile_name # So that the user does NOT need to delete all the time the file with the # calculated activation energies, I take it out of the list with the # filenames. This is the only exception from the rule stated above and the # reason why the outfile_name is hard coded. Over many runs it turned out # that this is a good thing to do. filenames = [ x for x in os.listdir(path) if '00000_activation' not in x.lower() ] print('') all_data = [] for filename in filenames: print("Working on {} ...".format(filename)) data = cd.Data(timestep, path + filename) data.in_kelvin = in_kelvin if not in_kelvin: print("Setting temperature to Kelvin ...") # create_temperature_in_kelvin() will be called even is the temperature # is already in Kelvin, because it contains a check if the data # actually has temperature data. This is just a check, which is probably # not necessary. data.create_temperature_in_kelvin() if not total_heat: print("Calculating total heat of reaction ...") data.calculate_total_heat_of_reaction() else: data.total_heat = deepcopy(total_heat) print("Calculating the conversion ...") data.calculate_conversion(total_heat, initial_conversion) data.conversion_step = conversion_step print( "Finding the time and temperature values for the integral limits ..." ) data.find_values_for_isoconversion() all_data.append(data) print('------') conversion_steps, activation_energies, \ control_parameters = calculate_activation_energy(all_data, \ initial_guess) with open(outfile, 'w') as f: this = 'conversion\tActivation Energy (J/mol)\tControl Parameter\n' f.write(this) for i in range(len(conversion_steps)): this = "{}\t{}\t{}\n".format(conversion_steps[i], \ activation_energies[i], control_parameters[i]) f.write(this) this = '\nA new file called < {} > '.format(outfile_name) that = 'was created in the same folder.' print(this + that)