コード例 #1
0
    def update_other_restriction_dict(self):
        """"Run when updating other restrictions (via other restriction editor)"""
        for i in self.mod.other_dict:
            disp_other = self.other_restr_editor.display_other_restrictions[i]
            ot = Other(
                disp_other.name_entry.get(),
                ast.literal_eval(disp_other.numerator_coefs_entry.get()
                                 ),  # Converts the string into a dictionary
                ast.literal_eval(disp_other.normalization_entry.get()),
                disp_other.def_low_entry.get(),
                disp_other.def_upp_entry.get(),
                disp_other.dec_pt_entry.get())
            self.mod.other_dict[i] = ot
            self.mod.restr_dict['other_' + i].name = ot.name
            self.mod.restr_dict['other_' + i].normalization = ot.normalization
            self.mod.restr_dict['other_' + i].default_low = ot.def_low
            self.mod.restr_dict['other_' + i].default_upp = ot.def_upp
            self.mod.restr_dict['other_' + i].dec_pt = ot.dec_pt

            self.mw.other_select_button[i].config(text=prettify(ot.name))
            self.display_restr_dict['other_' + i].set_name(prettify(ot.name))
            self.display_restr_dict['other_' + i].set_default_low(ot.def_low)
            self.display_restr_dict['other_' + i].set_default_upp(ot.def_upp)

        old_variables = copy.copy(self.mod.current_recipe.variables)
        # Reinsert stars next to other restrictions that are variables:
        for t, res in old_variables.items():
            if res[0:5] == 'other':
                self.display_restr_dict[res].select(t)

        self.mod.json_write_other()
        self.mod.json_write_restrictions()

        self.reset_relations = True
コード例 #2
0
    def calc_restrictions(self, recipe, restr_dict):   # first update recipe.
                                                       # Should be able to construct a reduced restr_dict from recipe
        t0 = time.process_time()
        
        # First, test for obvious errors
        
        if sum(self.oxide_dict[ox].flux for ox in recipe.oxides) == 0:
            messagebox.showerror(" ", 'No flux! You have to give a flux.')
            return
  
        # Run tests to see if the denominators of other restrictions are identically zero?

        for key in recipe.restriction_keys:
            if recipe.lower_bounds[key] > recipe.upper_bounds[key]:
                res = restr_dict[key]
                messagebox.showerror(" ", 'Incompatible ' + print_res_type(res.normalization) + 'bounds on ' + prettify(res.name))
                return

        delta = 0.1**9

        selected_fluxes = recipe.fluxes()

        sum_UMF_low = sum(recipe.lower_bounds['umf_'+ox] for ox in selected_fluxes)
        if sum_UMF_low > 1 + delta:
            messagebox.showerror(" ", 'The sum of the UMF flux lower bounds is '+str(sum_UMF_low)
                                       +'. It should be at most 1. Decrease one of the lower bounds by '+str(sum_UMF_low-1)
                                       +' or more.')     #will be a problem if they're all < sum_UMF_low-1))
            return

        sum_UMF_upp = sum(recipe.upper_bounds['umf_'+ox] for ox in selected_fluxes)            
        if sum_UMF_upp < 1 - delta:
            messagebox.showerror(" ", 'The sum of the UMF flux upper bounds is '+str(sum_UMF_upp)
                                       +'. It should be at least 1. Increase one of the upper bounds by '+str(1-sum_UMF_low)
                                       +' or more.')
            return

        for t in ['mass_perc_', 'mole_perc_']:
            sum_t_low = sum(recipe.lower_bounds[t+ox] for ox in recipe.oxides)
            if sum_t_low > 100 + delta:
                messagebox.showerror(" ", 'The sum of the ' + prettify(t) + ' lower bounds is '+str(sum_t_low)
                                           +'. It should be at most 100. Decrease one of the lower bounds by '+str(sum_t_low-100)
                                           +' or more.')     #will be a problem if they're all < sum_t_low-100)
                return

            sum_t_upp = sum(recipe.upper_bounds[t+ox] for ox in recipe.oxides)
            if  sum_t_upp < 100 - delta:
                messagebox.showerror(" ", 'The sum of the ' + prettify(t) + ' upper bounds is '+str(sum_t_upp)
                                           +'. It should be at least 100. Increase one of the upper bounds by '+str(100-sum_t_upp)
                                           +' or more.') 
                return
            
        sum_ing_low = sum(recipe.lower_bounds['ingredient_'+index] for index in recipe.ingredients)
        if sum_ing_low > 100 + delta:
            messagebox.showerror(" ", 'The sum of the ingredient lower bounds is '+str(sum_ing_low)
                                      +'. It should be at most 100. Decrease one of the lower bounds by '+str(sum_ing_low-100)
                                      +' or more.')     #will be a problem if they're all < sum_ing_low-100)
            return
            
        sum_ing_upp = sum(recipe.upper_bounds['ingredient_'+index] for index in recipe.ingredients)
        if sum_ing_upp < 100 - delta:
            messagebox.showerror(" ", 'The sum of the ingredient upper bounds is '+str(sum_ing_upp)
                                       +'. It should be at least 100. Increase one of the upper bounds by '+str(100-sum_ing_upp)
                                       +' or more.')  
            return
         
        #t0 = time.process_time()  
            
        for index in self.ingredient_dict:
            ing = 'ingredient_'+index
            if index in recipe.ingredients:
                ing_low = 0.01*recipe.lower_bounds[ing]
                ing_upp = 0.01*recipe.upper_bounds[ing]
            else:
                ing_low = 0
                ing_upp = 0
            self.constraints[ing+'_lower'] = self.lp_var[ing] >= ing_low*self.lp_var['ingredient_total']      # ingredient lower bounds    
            self.constraints[ing+'_upper'] = self.lp_var[ing] <= ing_upp*self.lp_var['ingredient_total']      # ingredient upper bounds


        t1 = time.process_time()      # The next section takes a while, perhaps because the dictionary self.lp_var is long.
                                      # May be better to split it.
         
        for ox in self.oxide_dict:          
            if ox in recipe.oxides:     
                self.constraints[ox+'_umf_lower'] = self.lp_var['mole_'+ox] >= recipe.lower_bounds['umf_'+ox]*self.lp_var['fluxes_total']   # oxide UMF lower bounds
                self.constraints[ox+'_umf_upper'] = self.lp_var['mole_'+ox] <= recipe.upper_bounds['umf_'+ox]*self.lp_var['fluxes_total']   # oxide UMF upper bounds
                self.constraints[ox+'_wt_%_lower'] = self.lp_var['mass_'+ox] >= 0.01*recipe.lower_bounds['mass_perc_'+ox]*self.lp_var['ox_mass_total']    # oxide weight % lower bounds
                self.constraints[ox+'_wt_%_upper'] = self.lp_var['mass_'+ox] <= 0.01*recipe.upper_bounds['mass_perc_'+ox]*self.lp_var['ox_mass_total']    # oxide weight % upper bounds
                self.constraints[ox+'_mol_%_lower'] = self.lp_var['mole_'+ox] >= 0.01*recipe.lower_bounds['mole_perc_'+ox]*self.lp_var['ox_mole_total']   # oxide mol % lower bounds
                self.constraints[ox+'_mol_%_upper'] = self.lp_var['mole_'+ox] <= 0.01*recipe.upper_bounds['mole_perc_'+ox]*self.lp_var['ox_mole_total']   # oxide mol % upper bounds

            else:
                try:
                    del self.constraints[ox+'_umf_lower']
                    del self.constraints[ox+'_umf_upper']
                    del self.constraints[ox+'_wt_%_lower']
                    del self.constraints[ox+'_wt_%_upper']
                    del self.constraints[ox+'_mol_%_lower']
                    del self.constraints[ox+'_mol_%_upper']
                except:
                    pass
                 
##        if 'KNaO' in self.oxides:
##            prob += self.lp_var['KNaO_umf'] == self.lp_var['K2O_umf'] + self.lp_var['Na2O_umf']     
##            prob += self.lp_var['KNaO_wt_%'] == lp_var['K2O_wt_%'] + lp_var['Na2O_wt_%']  

        for index in self.other_dict:
            if index in recipe.other:
                other_norm = self.linear_combination(self.other_dict[index].normalization)              
                self.constraints['other_'+index+'_lower'] = self.lp_var['other_'+index] >= recipe.lower_bounds['other_'+index]*other_norm   # lower bound
                self.constraints['other_'+index+'_upper'] = self.lp_var['other_'+index] <= recipe.upper_bounds['other_'+index]*other_norm   # upper bound
            else:
                try:
                    del self.constraints['other_'+index+'_lower']
                    del self.constraints['other_'+index+'_upper']
                except:
                    pass

# Finally, we're ready to calculate the upper and lower bounds imposed on all the variables

        calc_bounds = {-1:{}, 1:{}}
        for key in recipe.restriction_keys:
            res = restr_dict[key]
            norm = self.linear_combination(res.normalization)
            self.constraints['normalization'] = norm == 1  # Apply the normalization of the restriction in question
                                                           # Apparently this doesn't slow things down a whole lot
            for eps in [1, -1]:               # calculate lower and upper bounds.
                self += eps*self.lp_var[res.objective_func], res.name
                self.writeLP('constraints.lp')
                self.solve(solver)
                if self.status == 1:
                    calc_bounds[eps][key] = eps*pulp.value(self.objective)
                    #prob.writeLP('constraints.lp')
                else:
                    messagebox.showerror(" ", LpStatus[self.status])
                    self.writeLP('constraints.lp')
                    return
        t2 = time.process_time()  
        #print(t2 - t0)
        return {'lower':calc_bounds[-1], 'upper':calc_bounds[1]}
コード例 #3
0
    def __init__(self):
        self.mod = Model()

        self.mw = MainWindow()

        for button, t in [(self.mw.unity_radio_button, 'umf_'), \
                          (self.mw.percent_wt_radio_button, 'mass_perc_'), \
                          (self.mw.percent_mol_radio_button, 'mole_perc_')]:
            button.config(command=partial(self.update_oxide_entry_type, t))

        self.mw.file_menu.add_command(label="Recipes",
                                      command=self.open_recipe_menu)
        self.mw.file_menu.add_command(label="Save", command=self.save_recipe)
        self.mw.file_menu.add_command(label="Save as new recipe",
                                      command=self.save_new_recipe)

        #self.mw.options_menu.add_command(label="Edit Oxides", command=None)
        self.mw.options_menu.add_command(label="Edit Ingredients",
                                         command=self.open_ingredient_editor)
        self.mw.options_menu.add_command(
            label="Edit Other Restrictions",
            command=self.open_other_restriction_editor)
        #self.mw.options_menu.add_command(label="Restriction Settings", command=self.open_ingredient_editor)

        self.mw.calc_button.config(command=self.calc_restr)

        # Create and grid ingredient selection buttons:
        for r, i in enumerate(self.mod.order["ingredients"]):
            self.mw.ingredient_select_button[i] = ttk.Button(self.mw.ingredient_vsf.interior, text=self.mod.ingredient_dict[i].name, \
                                                             width=20, command=partial(self.toggle_ingredient, i))
            self.mw.ingredient_select_button[i].grid(row=r)

        # Create and grid other selection buttons:
        for r, j in enumerate(self.mod.order["other"]):
            self.mw.other_select_button[j] = ttk.Button(self.mw.other_vsf.interior, text=prettify(self.mod.other_dict[j].name), \
                                                        width=20, command=partial(self.toggle_other, j))
            self.mw.other_select_button[j].grid(row=r + 1)

        # Create DisplayRestriction dictionary
        self.display_restr_dict = {}
        for key in self.mod.restr_keys():
            self.display_restr_dict[key] = DisplayRestriction(self.mw.restriction_sf.interior, self.mw.x_lab, self.mw.y_lab, \
                                                              key, self.mod.restr_dict[key].name, self.mod.restr_dict[key].default_low, self.mod.restr_dict[key].default_upp)

        # Open default recipe.
        self.open_recipe('0')

        self.reset_relations = True
コード例 #4
0
    def calc_restrictions(self, recipe, restr_dict):

        # First, test for obvious errors

        for key in recipe.restriction_keys:
            if recipe.lower_bounds[key] > recipe.upper_bounds[key]:
                res = restr_dict[key]
                messagebox.showerror(
                    " ", 'Incompatible ' + print_res_type(res.normalization) +
                    'bounds on ' + prettify(res.name))
                return

        delta = 0.1**9

        selected_fluxes = recipe.fluxes()

        sum_UMF_low = sum(recipe.lower_bounds['umf_' + ox]
                          for ox in selected_fluxes)
        if sum_UMF_low > 1 + delta:
            messagebox.showerror(
                " ",
                'The sum of the UMF flux lower bounds is ' + str(sum_UMF_low) +
                '. It should be at most 1. Decrease one of the lower bounds by '
                + str(sum_UMF_low - 1) + ' or more.'
            )  #will be a problem if they're all < sum_UMF_low-1))
            return

        sum_UMF_upp = sum(recipe.upper_bounds['umf_' + ox]
                          for ox in selected_fluxes)
        if sum_UMF_upp < 1 - delta:
            messagebox.showerror(
                " ",
                'The sum of the UMF flux upper bounds is ' + str(sum_UMF_upp) +
                '. It should be at least 1. Increase one of the upper bounds by '
                + str(1 - sum_UMF_low) + ' or more.')
            return

        for t in ['mass_perc_', 'mole_perc_']:
            sum_t_low = sum(recipe.lower_bounds[t + ox]
                            for ox in recipe.oxides)
            if sum_t_low > 100 + delta:
                messagebox.showerror(
                    " ", 'The sum of the ' + prettify(t) +
                    ' lower bounds is ' + str(sum_t_low) +
                    '. It should be at most 100. Decrease one of the lower bounds by '
                    + str(sum_t_low - 100) + ' or more.'
                )  #will be a problem if they're all < sum_t_low-100)
                return

            sum_t_upp = sum(recipe.upper_bounds[t + ox]
                            for ox in recipe.oxides)
            if sum_t_upp < 100 - delta:
                messagebox.showerror(
                    " ", 'The sum of the ' + prettify(t) +
                    ' upper bounds is ' + str(sum_t_upp) +
                    '. It should be at least 100. Increase one of the upper bounds by '
                    + str(100 - sum_t_upp) + ' or more.')
                return

        sum_ing_low = sum(recipe.lower_bounds['ingredient_' + index]
                          for index in recipe.ingredients)
        if sum_ing_low > 100 + delta:
            messagebox.showerror(
                " ", 'The sum of the ingredient lower bounds is ' +
                str(sum_ing_low) +
                '. It should be at most 100. Decrease one of the lower bounds by '
                + str(sum_ing_low - 100) + ' or more.'
            )  #will be a problem if they're all < sum_ing_low-100)
            return

        sum_ing_upp = sum(recipe.upper_bounds['ingredient_' + index]
                          for index in recipe.ingredients)
        if sum_ing_upp < 100 - delta:
            messagebox.showerror(
                " ", 'The sum of the ingredient upper bounds is ' +
                str(sum_ing_upp) +
                '. It should be at least 100. Increase one of the upper bounds by '
                + str(100 - sum_ing_upp) + ' or more.')
            return

        t1 = time.process_time()
        # Inequalities:
        self.inequalities = []
        #ing_low = self._make_matrix(recipe.lower_bounds['ingredients'])
        #ing_upp = self._make_matrix(recipe.upper_bounds['ingredients'])
        ing_low = matrix([
            recipe.lower_bounds['ingredient_' + str(i)] / 100
            for i in self.current_ingredients
        ])
        ing_upp = matrix([
            recipe.upper_bounds['ingredient_' + str(i)] / 100
            for i in self.current_ingredients
        ])
        self.inequalities.append(
            self.lp_var['ingredient'] >= ing_low *
            self.lp_var['ingredient_total'])  # ingredient lower bounds
        self.inequalities.append(
            self.lp_var['ingredient'] <= ing_upp *
            self.lp_var['ingredient_total'])  # ingredient lower bounds

        #umf_lower = self._make_matrix(recipe.lower_bounds['umf'])
        #umf_upper = self._make_matrix(recipe.upper_bounds['umf'])
        umf_lower = matrix(
            [recipe.lower_bounds['umf_' + ox] for ox in self.current_oxides])
        umf_upper = matrix(
            [recipe.upper_bounds['umf_' + ox] for ox in self.current_oxides])
        self.inequalities.append(
            self.lp_var['mole'] >= umf_lower * self.lp_var['fluxes_total'])
        self.inequalities.append(
            self.lp_var['mole'] <= umf_upper * self.lp_var['fluxes_total'])
        #mol_perc_lower = self._make_matrix(0.01*recipe.lower_bounds['mole'])
        #mol_perc_upper = self._make_matrix(0.01*recipe.upper_bounds['mole'])
        mole_perc_lower = matrix([
            recipe.lower_bounds['mole_perc_' + ox] / 100
            for ox in self.current_oxides
        ])
        mole_perc_upper = matrix([
            recipe.upper_bounds['mole_perc_' + ox] / 100
            for ox in self.current_oxides
        ])
        self.inequalities.append(
            self.lp_var['mole'] >= mole_perc_lower *
            self.lp_var['ox_mole_total'])  # oxide mol % lower bounds
        self.inequalities.append(
            self.lp_var['mole'] <= mole_perc_upper *
            self.lp_var['ox_mole_total'])  # oxide mol % upper bounds
        #wt_perc_lower = self._make_matrix(0.01*recipe.lower_bounds['mass'])
        #wt_perc_upper = self._make_matrix(0.01*recipe.upper_bounds['mass'])
        mass_perc_lower = matrix([
            recipe.lower_bounds['mass_perc_' + ox] / 100
            for ox in self.current_oxides
        ])
        mass_perc_upper = matrix([
            recipe.upper_bounds['mass_perc_' + ox] / 100
            for ox in self.current_oxides
        ])
        self.inequalities.append(self.lp_var['mass'] >= mass_perc_lower *
                                 self.lp_var['ox_mass_total'])
        self.inequalities.append(self.lp_var['mass'] <= mass_perc_upper *
                                 self.lp_var['ox_mass_total'])

        for i, j in enumerate(self.current_other):
            res = restr_dict['other_' + j]
            normalization = self._linear_combination(res.normalization)
            other_lower = recipe.lower_bounds['other_' + j]
            other_upper = recipe.upper_bounds['other_' + j]
            self.inequalities.append(
                self.lp_var['other'][i] >= other_lower * normalization)
            self.inequalities.append(
                self.lp_var['other'][i] <= other_upper * normalization)

        # Calculate the upper and lower bounds imposed on all the variables:
        calc_bounds = {
        }  #{-1:{}, 1:{}}   # -1 for lower bounds, 1 for upper bounds
        for key in recipe.restriction_keys:
            calc_bounds[key] = {}
            res = restr_dict[key]
            norm = self._linear_combination(res.normalization)
            normalization = (
                norm == 1
            )  # Normalization of the restriction in question. There's a lot of
            # unnecessary repetition of this step, but it seems this doesn't
            # slow things down a whole lot
            opt_var = self._parser(res.objective_func)
            for eps, bound in zip(
                [1, -1],
                ['lower', 'upper']):  # calculate lower and upper bounds.
                lp = op(eps * opt_var,
                        self.relations + self.inequalities + [normalization])
                lp.solve(solver='glpk',
                         options={'glpk': {
                             'msg_lev': 'GLP_MSG_OFF'
                         }})
                if lp.status == 'optimal':
                    calc_bounds[key][bound] = eps * lp.objective.value()[0]
                else:
                    messagebox.showerror(" ", lp.status)
                    return 0

        return calc_bounds