"""NRV-:class:`.COMSOL_model` handling."""importconfigparserimportosimporttimeimportmphimportnumpyasnpfrom...backend._file_handlerimportrmv_extfrom...backend._log_interfaceimportrise_warningfrom...backend._parametersimportparametersfrom...utils._unitsimportVfrom._FEMimport*# built in COMSOL modelsdir_path=parameters.nrv_path+"/_misc"material_library=os.listdir(dir_path+"/comsol_templates/")################# Constants #################machine_config=configparser.ConfigParser()config_fname=dir_path+"/NRV.ini"machine_config.read(config_fname)COMSOL_Ncores=int(machine_config.get("COMSOL","COMSOL_CPU"))COMSOL_Status=machine_config.get("COMSOL","COMSOL_STATUS")=="True"fem_verbose=True
[docs]classCOMSOL_model(FEM_model):""" A class for COMSOL Finite Element Models, inherits from FEM_model. """
[docs]def__init__(self,fname,n_proc=None,handle_server=False):""" Creates a instance of a COMSOL Finite Element Model object. Parameters ---------- fname : str path to the COMSOL (.mph) model file n_proc : int number of COMSOL cores for computation. If None is specified, this number is taken from the NRV2.ini configuration file. Byu default set to None handle_server : bool if True, the instantiation creates the server, else a external server is used. Usefull for multiple cells sharing the same model """ifCOMSOL_Status:t0=time.time()super().__init__(n_proc=n_proc)self.type="COMSOL"self.model_path=fnamef_in_librairy=rmv_ext(str(fname))+".mph"self.__has_client=Falseself.__has_server=Falseiff_in_librairyinmaterial_library:self.fname=dir_path+"/comsol_templates/"+f_in_librairyelse:self.fname=fname# self.model_path = fnameifself.n_procisNone:self.n_proc=COMSOL_Ncoresself.handle_server=handle_server# start client and serverpass_info("Starting COMSOL server/client, this may take few seconds")ifself.handle_server:self.server=mph.Server(cores=self.n_proc)self.__has_server=Trueelse:self.server=Noneself.client=mph.start(cores=self.n_proc)self.__has_client=Trueself.client.caching(True)pass_info("... loading the COMSOL model")self.model=self.client.load(self.fname)# self.client.caching(True)# sourceself.fname=fnameself.setup_timer+=time.time()-t0else:## COMSOL TURNED OFF, no error, but only a warning and no computation (exit)rise_warning("Bad implementation, a COMSOL simulation is implemented while NRV2 has COMSOL status turned OFF, unterminated computation, early exit without error",abort=True,)
[docs]defsave(self):""" Save the changes to the model file. (Avoid for the overal weight of the package) """self.model.save()
[docs]defclear(self):""" Clear the mesh and result section of the model """self.model.clear()self.model.reset()
[docs]defclose(self):""" Close the FEM simulation and the COMSOL link """ifself.__has_client:self.client.disconnect()delself.clientself.__has_client=Falseifself.handle_serverorself.__has_server:self.server.stop()delself.serverself.__has_server=False
def__del__(self):self.close()super().__del__()############################### Access model parameters ###############################
[docs]defget_parameters(self):""" Get the all the parameters in the model as a python dictionary. Returns ------- parameters all parameters as dictionnary, names a keys, with corresponding values """returnself.model.parameters()
[docs]defget_parameter(self,p_name):""" Get a specific parameter Returns ------- str value of the parameter as in COMSOL (with unit) """returnself.model.parameter(p_name)
[docs]defset_parameter(self,p_name,p_value):""" Set a parameter to a desired value Parameters ---------- p_name : str parameter name in the COMSOL model p_value : str parameter value as in COMSOL, with unit """self.model.parameter(p_name,p_value)
##################### Use the model #####################
[docs]defget_meshes(self):""" Get the different meshes implemented in the model Returns ------- list list of meshes implemented in the COMSOL model file """returnself.model.meshes()
[docs]defbuild_and_mesh(self):""" Build the geometry and perform meshing process """t0=time.time()pass_info("... Building model geometry")self.model.build()pass_info("... Meshing geometry")self.model.mesh()self.is_meshed=Trueself.meshing_timer+=time.time()-t0
[docs]defsolve(self):""" Solve the model """ifnotself.is_meshed:self.build_and_mesh()pass_info("... Solving model")t0=time.time()self.model.solve()self.is_computed=Trueself.solving_timer+=time.time()-t0
[docs]defget_potentials(self,x,y,z):""" Get the potential on a line to get extracellular potential for axons stimulation. Parameters ---------- x : np.array array of x coordinates in the model y : float y-coordinate of the axon z : float z-coordinate of the axon Returns: -------- array All potential for all paramtric sweeps (all electrodes in NRV2 models)\ (line: electrode selection, column: potential) """t0=time.time()COMSOL_expressions=["at3("+str(x[k])+"[um], "+str(y)+"[um], "+str(z)+"[um], V)"forkinrange(len(x))]Voltage=self.model.evaluate(COMSOL_expressions)*Vself.access_res_timer+=time.time()-t0# transpose to be consistent check if no BUG generatedreturnnp.asarray(Voltage).T
[docs]defexport(self,path=""):""" Export the figures of the COMSOL results and posprocess (in PNG format) Parameters ---------- path : str path address where to save graphics """exports=self.model.exports()forexportinexports:self.model.export(export,path+export+".png")