{"id":315,"date":"2023-07-14T10:48:17","date_gmt":"2023-07-14T08:48:17","guid":{"rendered":"https:\/\/logbooks.ifosim.org\/finesse\/?p=315"},"modified":"2023-07-14T10:48:17","modified_gmt":"2023-07-14T08:48:17","slug":"creating-a-composite-component","status":"publish","type":"post","link":"https:\/\/logbooks.ifosim.org\/finesse\/2023\/07\/14\/creating-a-composite-component\/","title":{"rendered":"Creating a composite component"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>import finesse\nfrom finesse.components import Mirror, Space, Laser\nfrom finesse.parameter import float_parameter, bool_parameter\nfrom finesse.element import ModelElement\nfrom finesse.freeze import Freezable\nimport numpy as np\nimport matplotlib.pyplot as plt<\/code><\/pre>\n\n\n\n<p>Here&#8217;s an example on  how to create composite objects in Finesse 3. Below we create a thick mirror that better defines the AR, substrate, and HR surface. Internally this thick mirror is made from two thin mirrors plus a space. These are added to the model when the `_on_add` method is called just after the composite object is added to a model. This interface is quite generic and internal connections and features of the components can be exposed or not. For example here we limit the AR surface to only ever use a loss.<\/p>\n\n\n\n<p>Parameters are added to the composite element and the symbolically referenced to the internal components. Although there are geometric <code>Parameters<\/code> defined in the composite object, these are marked as false, as they simply map to the real geometric parameters of the component parts. Before adding the composite components we also modify where they will be stored in the namespace of the model. They are not added to the main model namspace to save confusion, but to the composite `.components`  namespace.<\/p>\n\n\n\n<p>Below we also redefine what the ports are called. The thick mirror has an AR and HR port, or alternatively a front and back port.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@float_parameter(\"Rc\", \"HR radius of curvature\", units=\"m\", is_geometric=False)\n@float_parameter(\"Rc_AR\", \"AR radius of curvature\", units=\"m\", is_geometric=False)\n@float_parameter(\"thickness\", \"Thickness\", units=\"m\", is_geometric=False)\n@float_parameter(\"nr\", \"Substrate refractive index\", units=\"\", is_geometric=False)\n@float_parameter(\"R\", \"HR reflectivity\", units=\"\", is_geometric=False)\n@float_parameter(\"T\", \"HR transmissivity\", units=\"\", is_geometric=False)\n@float_parameter(\"L\", \"HR loss\", units=\"\", is_geometric=False)\n@float_parameter(\"R_AR\", \"AR reflectivity\", units=\"\", is_geometric=False)\n@float_parameter(\"phi\", \"Tuning\", units=\"degrees\", is_geometric=False)\n@float_parameter(\"xbeta\", \"Yaw misalignment\", units=\"radians\")\n@float_parameter(\"ybeta\", \"Pitch misalignment\", units=\"radians\")\n@bool_parameter(\"misaligned\", \"Misaligns mirror reflection (R=0 when True)\")\nclass ThickMirror(ModelElement):\n    def __init__(self, name, R=0.99, T=0.01, L=0, R_AR=0, phi=0, Rc=np.inf, Rc_AR=np.inf, thickness=0, nr=1, misaligned=False, xbeta=0, ybeta=0):\n        super().__init__(name)\n        self.phi.value = phi\n        self.xbeta.value = xbeta\n        self.ybeta.value = ybeta\n        self.misaligned.value = misaligned\n        self.R.value = R\n        self.T.value = T\n        self.L.value = L\n        self.Rc.value = Rc\n\n        self.thickness.value = thickness\n        self.nr.value = nr\n\n        self.R_AR.value = R_AR\n        self.Rc_AR.value = Rc_AR\n\n        self.components = Freezable()\n\n    @property\n    def fr(self):\n        return getattr(self.components, f\"{self.name}_front\").p1\n    \n    @property\n    def bk(self):\n        return getattr(self.components, f\"{self.name}_back\").p2\n\n    @property\n    def HR(self):\n        return getattr(self.components, f\"{self.name}_front\").p1\n    \n    @property\n    def AR(self):\n        return getattr(self.components, f\"{self.name}_back\").p2\n\n    def _on_add(self, model):\n        back = Mirror(f\"{self.name}_back\", Rc=self.Rc_AR.ref, R=0, L=self.R_AR.ref, T=1-self.R_AR.ref, phi=self.phi.ref, misaligned=self.misaligned.ref, xbeta=self.xbeta.ref, ybeta=self.ybeta.ref)\n        front = Mirror(f\"{self.name}_front\", Rc=self.Rc.ref, R=self.R.ref, T=self.T.ref, L=self.L.ref, phi=self.phi.ref, misaligned=self.misaligned.ref, xbeta=self.xbeta.ref, ybeta=self.ybeta.ref)\n\n        back._namespace = (f\".{self.name}.components\", )\n        front._namespace = (f\".{self.name}.components\", )\n\n        model.add(back, unremovable=True)\n        model.add(front, unremovable=True)\n\n        substrate = Space(f\"{self.name}_substrate\", back.p1, front.p2, L=self.thickness.ref, nr=self.nr.ref)\n        substrate._namespace = (\".spaces\", f\".{self.name}.components\")\n        model.add(substrate, unremovable=True)<\/code><\/pre>\n\n\n\n<p>To use it we simply add it to the model and then connect up the ports as required. We can then interact with the composite component parameters, such as scanning the cavity length, in the usual ways.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>model = finesse.Model()\nL0 = model.add(Laser('L0'))\nITM = model.add(ThickMirror('ITM'))\nETM = model.add(ThickMirror('ETM'))\nmodel.link(L0.p1, ITM.AR)\nmodel.link(ITM.HR, ETM.HR)\nmodel.parse(\"pd P ITM.HR.i\")\n\nout = model.run(\"xaxis(ETM.phi, lin, -90, 90, 100)\")\nplt.semilogy(out.x1, out&#091;'P']<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here&#8217;s an example on how to create composite objects in Finesse 3. Below we create a thick mirror that better defines the AR, substrate, and HR surface. Internally this thick mirror is made from two thin mirrors plus a space. These are added to the model when the `_on_add` method is called just after the [&hellip;]<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ssl_alp_hide_revisions":false,"footnotes":"","ssl_alp_hide_crossreferences_to":false},"categories":[1],"tags":[],"ssl-alp-coauthor":[38],"class_list":["post-315","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/posts\/315","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/comments?post=315"}],"version-history":[{"count":1,"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/posts\/315\/revisions"}],"predecessor-version":[{"id":322,"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/posts\/315\/revisions\/322"}],"wp:attachment":[{"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/media?parent=315"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/categories?post=315"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/tags?post=315"},{"taxonomy":"ssl-alp-coauthor","embeddable":true,"href":"https:\/\/logbooks.ifosim.org\/finesse\/wp-json\/wp\/v2\/ssl-alp-coauthor?post=315"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}