"""NRV-:class:`.Problem` handling."""importnumpyasnpimportfaulthandlerimporttracebackfromrich.progressimportProgress,SpinnerColumn,BarColumn,TextColumn,TimeRemainingColumnfrom..backend._parametersimportparametersfrom..backend._NRV_ClassimportNRV_classfrom..backend._NRV_Mprocimportget_poolfrom..backend._log_interfaceimportrise_error,pass_debug_info,set_log_levelfrom.optim_utils._OptimResultsimportoptim_resultsfrom._CostFunctionsimportcost_functionfrom._OptimizersimportOptimizerimportsys# enable faulthandler to ease 'segmentation faults' debugfaulthandler.enable()
[docs]classProblem(NRV_class):""" Problem Class A class to describe problems that should be optimized with the NRV Framework. The problem should be described with a simulation and a cost, using the object cost_function, and various optimization algorithms can be used to find optimal solution. This class is abstract and is not supposed to be used directly by the end user. NRV can handle two types of problems: - problems where a geometric parameter can be optimized: please refer to ... - problems where the waveform can be optimized: please refer to ... """
[docs]def__init__(self,cost_function:cost_function=None,optimizer:Optimizer=None,save_problem_results:bool=False,problem_fname:str="optim.json",n_proc:int=None,):super().__init__()self._CostFunction=cost_functionself._Optimizer=optimizer# For cases where optimisation is done on a swarm(groupe) of particleself.swarm_optimizer=False# self._SwarmCostFunction = Noneself.save_problem_results=save_problem_resultsself.problem_fname=problem_fnameself.mp_type=Noneself.n_proc=n_procorparameters.optim_Ncores
# Handling the cost_function attribute@propertydefcostfunction(self)->cost_function:""" Cost function of a Problem, the cost function should be a CosFunction object, it should return a scalar. NRV function should be prefered """returnself._CostFunction@costfunction.setterdefcostfunction(self,cf:cost_function):# need to add a verification that the cost function is a scallar and so onself._CostFunction=cf@costfunction.deleterdefcostfunction(self):self._CostFunction=Nonedef_SwarmCostFunction(self,swarm):s_l=len(swarm)costs=np.zeros((s_l))ifself.mp_type=="costfunction":foriinrange(s_l):particle=swarm[i][:]costs[i]=self._CostFunction(particle)else:#LR: This still generate PETSC errors (not crashing the script tho). Adding pool.close()/pool.join() crashes everything howeverwithget_pool(n_jobs=self.n_proc)aspool:fori_c,costinenumerate(pool.imap(self._CostFunction,swarm)):costs[i_c]=costreturncosts
# Handling the Optimizer attribute@propertydefoptimizer(self):""" Optimizer of the problem, the Optimizer should be an Optimizer object. It has reference to optimization methods and constraints """returnself._Optimizer@optimizer.setterdefoptimizer(self,optim:Optimizer):self._Optimizer=optimself.swarm_optimizer=self._Optimizer.swarm_optimizer@optimizer.deleterdefoptmizer(self):# self._Optimizer = Nonepass# Call method is where the magic happensdef__call__(self,**kwargs)->optim_results:""" Perform the optimization: minimze the `cost_function` using `optmizer` Parameters ---------- kwargs containing parameters of the optimizer to change Returns ------- optim_results results of the optimization Raises ------ KeyboardInterrupt """try:kwargs=self.__update_saving_parameters(**kwargs)ifself.mp_typeisNone:self.set_multiprocess_type()ifnotself.swarm_optimizer:results=self._Optimizer(self._CostFunction,**kwargs)else:results=self._Optimizer(self._SwarmCostFunction,**kwargs)results["status"]="Completed"exceptKeyboardInterrupt:raiseKeyboardInterruptexcept:results["status"]="Error"rise_error(traceback.format_exc())set_log_level("INFO")ifself.save_problem_results:results.save(save=True,fname=self.problem_fname)returnresults# Mcore handlingdef__check_m_proc_CostFunction(self):""" check if a cost funciton can be parallelized """ifisinstance(self._CostFunction,cost_function):returnself._CostFunction.is_m_proc_funcelse:returnFalse
[docs]defset_multiprocess_type(self,costfunction_mp=True,n_core=None):""" Set if multiprocessing should be applied to the optimizaiton or the CostFunction simulation Warning ------- For now, only costfunction can be parallelized. This will be improve in the future """ifn_coreisnotNone:self.n_proc=n_core# parallelizable optimizerif"n_processes"inself._Optimizer.__dict__:ifself.__check_m_proc_CostFunction()andcostfunction_mp:#* To add number of n_core_fascicle = n_coreself._Optimizer.n_processes=Noneself.mp_type="costfunction"else:#* To add number of n_core_fascicle = 1#!! Bug cannot compute local method generated from cost_function_swarm_from_particleself._Optimizer.n_processes=self.n_proc#!!self._Optimizer.n_processes = Noneself.mp_type="optimizer"else:#* To add number of n_core_fascicle = n_coreself.mp_type="costfunction"
# additional methodsdef__update_saving_parameters(self,**kwargs):""" internal use only: update the results saving parameters and remove the corresponding keys from kwargs """if"save_problem_results"inkwargs:self.save_problem_results=kwargs.pop("save_problem_results")if"problem_fname"inkwargs:self.problem_fname=kwargs.pop("problem_fname")returnkwargs