"""Flows for calculating the polarization of a polar material."""from__future__importannotationsimportloggingfromdataclassesimportdataclass,fieldfromtypingimportTYPE_CHECKINGfromjobflowimportFlow,MakerifTYPE_CHECKING:frompathlibimportPathfrompymatgen.core.structureimportStructurefromatomate2.vasp.jobs.baseimportBaseVaspMakerfromatomate2.vasp.flows.coreimportDoubleRelaxMakerfromatomate2.vasp.jobs.coreimportPolarizationMaker,RelaxMakerfromatomate2.vasp.jobs.ferroelectricimport(add_interpolation_flow,get_polarization_output,interpolate_structures,polarization_analysis,)__all__=["FerroelectricMaker"]logger=logging.getLogger(__name__)
[docs]@dataclassclassFerroelectricMaker(Maker):""" Maker to calculate polarization of a polar material. Parameters ---------- name : str Name of the flows produced by this maker. nimages: int Number of interpolated structures calculated from polar to nonpolar structures relax_maker: BaseVaspMaker or None or tuple None to avoid relaxation of both polar and nonpolar structures BaseVaspMaker to relax both structures (default) tuple of BaseVaspMaker and None to control relaxation for each structure lcalcpol_maker: BaseVaspMaker Vasp maker to compute the polarization of each structure """name:str="ferroelectric"nimages:int=8relax_maker:BaseVaspMaker|None|tuple=field(default_factory=lambda:DoubleRelaxMaker.from_relax_maker(RelaxMaker()))lcalcpol_maker:BaseVaspMaker=field(default_factory=PolarizationMaker)
[docs]defmake(self,polar_structure:Structure,nonpolar_structure:Structure,prev_vasp_dir:str|Path|None=None,)->Flow:""" Make flow to calculate the polarization. Parameters ---------- polar_structure : .Structure A pymatgen structure of the polar phase. nonpolar_structure : .Structure A pymatgen structure of the nonpolar phase. prev_vasp_dir : str or Path or None A previous vasp calculation directory to use for copying outputs. """jobs=[]prev_vasp_dir_p,prev_vasp_dir_np=None,Noneifnotisinstance(self.relax_maker,tuple):self.relax_maker=(self.relax_maker,self.relax_maker)ifself.relax_maker[0]:# optionally relax the polar structurerelax_p=self.relax_maker[0].make(polar_structure)relax_p.append_name(" polar")jobs.append(relax_p)polar_structure=relax_p.output.structureprev_vasp_dir_p=relax_p.output.dir_namelogger.info(f"{type(polar_structure)}")polar_lcalcpol=self.lcalcpol_maker.make(polar_structure,prev_dir=prev_vasp_dir_p)polar_lcalcpol.append_name(" polar")jobs.append(polar_lcalcpol)polar_structure=polar_lcalcpol.output.structureifself.relax_maker[1]:# optionally relax the nonpolar structurerelax_np=self.relax_maker[1].make(nonpolar_structure)relax_np.append_name(" nonpolar")jobs.append(relax_np)nonpolar_structure=relax_np.output.structureprev_vasp_dir_np=relax_np.output.dir_namenonpolar_lcalcpol=self.lcalcpol_maker.make(nonpolar_structure,prev_dir=prev_vasp_dir_np)nonpolar_lcalcpol.append_name(" nonpolar")jobs.append(nonpolar_lcalcpol)nonpolar_structure=nonpolar_lcalcpol.output.structureinterp_structs_job=interpolate_structures(polar_structure,nonpolar_structure,self.nimages)jobs.append(interp_structs_job)interp_structs=interp_structs_job.outputadd_interp_flow=add_interpolation_flow(interp_structs,self.lcalcpol_maker)pol_analysis=polarization_analysis(get_polarization_output(nonpolar_lcalcpol),get_polarization_output(polar_lcalcpol),add_interp_flow.output,)jobs.append(add_interp_flow)jobs.append(pol_analysis)returnFlow(jobs=jobs,output=pol_analysis.output,name=self.name,)