Frequently Asked Questions: Photonic Canvas
Photonic Canvas keeps your design, your PDK version, your simulation results and your measured data together in one project, with versions and traceability.
Photonic Canvas projects need a Flexcompute account. Photonic Canvas is part of PhotonForge Enterprise.
In this notebook, you will learn how to:
- make a project, open it again, and add your components, your PCell code and a PDK,
- keep simulation files and measurement data with a component, and a DRC deck with the technology,
- give a component, a technology or the whole project a numbered version,
- share the project, and see when a colleague changes a component,
- go back to an earlier version or to an earlier save,
- see the whole project, its history and its files at one time.
Run the questions in sequence, from top to bottom. Each question uses the results of the questions before it. The notebook runs no simulations. It takes approximately two minutes.
Before you start
Section titled “Before you start”- Install PhotonForge and set your Flexcompute API key.
- Put the folder
misc/next to this notebook. It contains the PCell file and the small files that the questions attach:waveguide_bend.py,design_review.txt,bend_sweep.py,basic_technology.drc,basic_technology_v2.drcandbend_loss.csv. - Each run makes a new project in your account. The last section tells you how to remove it.
Everything in one place
Section titled “Everything in one place”A Photonic Canvas project works like a shared folder in a cloud drive:

There are two differences:
- Your notebook works on its own copy of the project. Other people do not type into your
copy live. Before you save, look for saves from other people with
changed_since()(question 14). - A file that you keep in the project does not change. To change a file, attach a new file.
For photonics, this gives one place for all the parts of a tape-out, with their history: every save, and the versions that you name.

Glossary
Section titled “Glossary”| Term | Meaning |
|---|---|
| project | The shared place for one piece of work, for example a tape-out. The project is on the server. You open it with its id. |
| component | A layout in the project, for example a bend or a reticle. You find a component by its name. |
| cell | A component that is placed in another component, for example one of the nine gratings on a reticle. |
| technology | The process stack that a component uses: layers, thicknesses and waveguide types. |
| PCell | A Python function that makes a component from its parameters, for example waveguide_bend(radius=3.0). |
| source | The Python files in the project that contain your PCells. add_module_file() adds a file. A colleague runs import_module(globals()) one time, and the PCells are ready to use. A change to these files counts only after you save it. The tree shows unsaved changes in orange. |
| library | A version of another project that you add to your project, for example a foundry PDK. You can then use its cells and its technology. |
| file | Anything that you keep in the project, for example a simulation script, a GDS file or measurement data. A file does not change after you attach it. |
| target | The component or technology that a file belongs to. Use its name or the object. With no target, the file belongs to the whole project. |
| tag | A label on a file, for example simulation or measurement. You use tags to find files again. |
| version tag | The tag version:1.0.0 on a file. It tells which version the file belongs to. |
| save | One add() or update(). The server gets it immediately and keeps it. |
| version | A number that you give to one save, for example 1.0.0, with a message. The history records who made it and when. Anyone can rebuild it later. |
| marker | The point where a component was when you looked at it. Later, changed_since(marker) tells you if the component changed. |
Commands that show the project
Section titled “Commands that show the project”These commands only read. You can run them at any time.
| To see | Run |
|---|---|
| what is in the project | project.tree(), or print(project.tree()) for text |
| one component, with all its cells and files | project.tree(target="bend") |
| all versions, with their dates | project.version_history() |
| which file belongs to which version | project.traceability_matrix() |
| every save of a component | project.edit_log("bend") |
| the saves after you looked | project.changed_since(marker) |
Import PhotonForge and its project interface, pda. Use the demo technology of
PhotonForge as the default technology.
The questions use 6 small files. Download them into a folder named misc next to this notebook: basic_technology.drc, basic_technology_v2.drc, bend_loss.csv, bend_sweep.py, design_review.txt, waveguide_bend.py.
import subprocessimport sysimport tempfileimport timefrom pathlib import Path
import photonforge as pffrom photonforge import pda
# the demo process stack of PhotonForgepf.config.default_technology = pf.basic_technology()Two short functions help in the questions below:
compare()shows components next to each other, at the same scale.run_colleague()acts as a colleague. It starts a second Python program. That program opens the project and saves changes, as a person on a different computer does.
def compare(*pairs): """Show components next to each other, at the same scale, with titles.
Example: compare(("now", a), ("at 1.0.0", b)) """ heights = [c.bounds()[1][1] - c.bounds()[0][1] for _, c in pairs] text_size = 0.08 * max(heights) + 0.4 picture = pf.Component("compare") x = 0.0 for title, component in pairs: (x0, y0), (x1, y1) = component.bounds() # align the tops of the components picture.add(pf.Reference(component.copy(), origin=(x - x0, -y1))) picture.add("METAL", *pf.text(title, text_size, (x, 1.5 * text_size))) x += (x1 - x0) + 4 * text_size return picture
COLLEAGUE = '''import sys, timefrom photonforge import pda
project = pda.load_project(project_id=sys.argv[1]) # open the projectproject.import_module(globals()) # get its PCell codename = sys.argv[2]for change in sys.argv[3:]: # save each change alone key, value = change.split("=") component = project.component(name) component.update(**{key: float(value)}) print("saved at", time.time(), flush=True) project.update(component) time.sleep(6)'''
def run_colleague(project_id, name, *changes): """Run the program of the colleague, and wait until it stops.
Each change is one save, for example "radius=5.0". Returns the times at which the colleague sent the saves. """ folder = Path(tempfile.mkdtemp()) # a different folder: a different computer script = folder / "colleague.py" script.write_text(COLLEAGUE) done = subprocess.run( [sys.executable, str(script), project_id, name, *changes], cwd=folder, capture_output=True, text=True, timeout=300, ) if done.returncode != 0: raise RuntimeError(done.stderr[-2000:]) return [float(line.split()[-1]) for line in done.stdout.splitlines() if line.startswith("saved at")]A. Your project
Section titled “A. Your project”1. What is a project?
Section titled “1. What is a project?”A project is the shared place for one piece of work, for example a tape-out. It contains your components, their technology, the PCell code, the files that you keep with them, and their versions. The project is on the server. Your notebook works on a copy of it.
project = pda.create_project("FAQ project") # make a new private projectprint("name:", project.name)print("id :", project.id) # you and your colleagues open the project with itname: FAQ projectid : T5Qb3m8XRcTQfEq79437hHXSaDb2. How do I open the project again?
Section titled “2. How do I open the project again?”Use its id. Each id is unique, but two projects can have the same name. Keep the id with your work, for example in a file next to the notebook.
Path("project_id.txt").write_text(project.id) # keep the id in a file
# open the project again, today or next weeksame = pda.load_project(project_id=Path("project_id.txt").read_text())print("opened:", same.name)opened: FAQ projectpda.list_projects() can also find a project by its name. But it opens every project
that you can see, so it is slow when you have many projects.
3. How do I add a component?
Section titled “3. How do I add a component?”Make the component, give it a name, and add it with add(). Later calls find the
component by this name.
The server gets each save immediately. add() and update() are the saves. There is no
separate upload step. Each person who opens the project gets your save.
straight = pf.Component("straight_wg") # its name in the projectstraight.add("WG_CORE", pf.Rectangle(center=(0, 0), size=(10, 0.5))) # 10 umproject.add(straight) # save it in the project# Watch out: add() works one time for each name.# To save a changed component later, use update().
project.component("straight_wg") # get it back by its nameNow the project has its technology and one component. Each box shows its kind in small letters, above a line. Each kind has its own color: technology (blue), library (purple), source (gray), component (green) and file (orange).
project.tree()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}}}%%
flowchart TB
n0(["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>PROJECT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>FAQ project"]);
n1["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>TECHNOLOGY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>Basic Technology"];
n2["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>straight_wg<br/><b>not versioned</b>"];
n0 --> n1
n0 --> n2
classDef project fill:#e4efe9,stroke:#00643c
class n0 project
classDef component fill:#e4efe9,stroke:#00643c
class n2 component
classDef technology fill:#e9f0f8,stroke:#3a6ea5
class n1 technology
4. How do I add my PCell code?
Section titled “4. How do I add my PCell code?”A PCell is Python code. To change a component that a PCell made, you need that code.
Without the code, a colleague can see the bend but cannot set a new radius. So put the
code in the project. add_module_file() copies your .py file into the project and gives
it back to you, ready to use.
Our PCell is in misc/waveguide_bend.py. It makes a 90 degree bend with two parameters,
radius and width:
print(Path("misc/waveguide_bend.py").read_text())"""A waveguide bend PCell with two parameters: radius and width."""
import photonforge as pfimport photonforge.typing as pft
__version__ = "1.0"
@pf.parametric_componentdef waveguide_bend( *, radius: pft.PositiveDimension = 3.0, width: pft.PositiveDimension = 0.5): """A 90 degree bend: a quarter of a ring, so radius and width show.""" c = pf.Component("bend") # the name of the component in the project ring = pf.Circle( radius=radius + width / 2, inner_radius=radius - width / 2, sector=(0, 90) ) c.add("WG_CORE", ring) return c# Watch out: if a colleague changed the project code after you opened the# project, this call stops with an error. Then call project.load_latest()# first, so that you do not write over their files.# add the PCell file to the projectbend_code = project.add_module_file("misc/waveguide_bend.py")
bend = bend_code.waveguide_bend(radius=3.0) # make one bend with the PCellproject.add(bend) # save it: its name is "bend"time.sleep(3) # add() returns a moment before the server has the bendbendA colleague uses the code. The colleague opens the project and runs
import_module(globals()) one time. This gets the project code and makes it ready to use
in their notebook. Now the colleague can change the parameters of the bend.
colleague = pda.load_project(project_id=project.id) # a colleague opens it# Watch out: import_module(globals()) adds a module with the name of each# project ("faq_project" here). A variable with the same name is replaced.colleague.import_module(globals()) # get the project code, one time per session
theirs = colleague.component("bend")theirs.update(radius=5.0) # a new radius: this needs the PCell codetheirs # their own copy: nothing is savedNow the project also has the bend, and the source that makes it.
project.tree()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}}}%%
flowchart TB
n0(["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>PROJECT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>FAQ project"]);
n1["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>TECHNOLOGY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>Basic Technology"];
n2[["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>SOURCE</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>1 file<br/>waveguide_bend.py"]];
n3["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>straight_wg<br/><b>not versioned</b>"];
n4["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>bend<br/><b>not versioned</b>"];
n0 --> n1
n0 --> n2
n0 --> n3
n0 --> n4
classDef project fill:#e4efe9,stroke:#00643c
class n0 project
classDef component fill:#e4efe9,stroke:#00643c
class n3,n4 component
classDef technology fill:#e9f0f8,stroke:#3a6ea5
class n1 technology
classDef source fill:#eef1f3,stroke:#4a5b64
class n2 source
5. How do I add a PDK?
Section titled “5. How do I add a PDK?”A foundry PDK is published as a library: a version of another project. Add the library to your project. Then you can use its cells and its technology by their names, next to your own components.
# Find the library by its name, then add it with its id.# Watch out: a search by name opens every project that you can see, so it# can be slow. Do the search one time and keep the id.versions = pda.list_libraries(name="SiEPIC EBeam", latest=False) # all versionssiepic_id = next(v["id"] for v in versions if v["version"] == "1.2.2")
project.add_library(library_id=siepic_id) # add the PDK to the projectproject.import_module(globals()) # get the code of the PDK
gc = project.component("ebeam_gc_te1550") # a cell of the PDK, by its nameprint("cell:", gc.name, "| technology:", gc.technology.name)gccell: ebeam_gc_te1550 | technology: SiEPIC EBeam SiNow the library is next to our own technology, source and components. The cells of the library stay in the library. The project uses them by their names.
project.tree()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}}}%%
flowchart TB
n0(["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>PROJECT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>FAQ project"]);
n1["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>TECHNOLOGY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>Basic Technology"];
n2("<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>LIBRARY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>SiEPIC EBeam");
n3[["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>SOURCE</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>1 file<br/>waveguide_bend.py"]];
n4["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>straight_wg<br/><b>not versioned</b>"];
n5["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>bend<br/><b>not versioned</b>"];
n0 --> n1
n0 --> n2
n0 --> n3
n0 --> n4
n0 --> n5
classDef project fill:#e4efe9,stroke:#00643c
class n0 project
classDef component fill:#e4efe9,stroke:#00643c
class n4,n5 component
classDef technology fill:#e9f0f8,stroke:#3a6ea5
class n1 technology
classDef library fill:#f0ebf8,stroke:#6b4cc4
class n2 library
classDef source fill:#eef1f3,stroke:#4a5b64
class n3 source
B. Files and versions
Section titled “B. Files and versions”6. How do I keep a file with the project?
Section titled “6. How do I keep a file with the project?”Use attach() with no target. The file then belongs to the whole project. This is
correct for a file about the whole project, for example a design review.
# no target: the file belongs to the whole projectreview = project.attach("misc/design_review.txt", tags=["review"])print(review["filename"], review["tags"])design_review.txt ['review']7. How do I keep a file with a component?
Section titled “7. How do I keep a file with a component?”Use two arguments:
targettells which component the file belongs to. Use the name of the component. Question 10 uses a technology as the target. With notarget, as in question 6, the file belongs to the whole project.tagsis a list of your own labels. You use them to find the file again. Use words that your team agrees on, for examplesimulation,measurementorgds. One tag has a special meaning: the version tagversion:1.0.0tells which version the file belongs to (question 8).
# The file belongs to the bend. Its tag is "simulation".project.attach("misc/bend_sweep.py", target="bend", tags=["simulation"])
# find the file again by its tagfor f in project.attachments(target="bend", tags=["simulation"]): print(f["filename"], f["tags"])bend_sweep.py ['simulation']Now there is one file on the project and one file on the bend. Neither file belongs to a version yet (“no version”).
project.tree()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}}}%%
flowchart TB
n0(["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>PROJECT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>FAQ project"]);
n1["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>TECHNOLOGY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>Basic Technology"];
n2("<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>LIBRARY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>SiEPIC EBeam");
n3[["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>SOURCE</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>1 file<br/>waveguide_bend.py"]];
n4>"design_review.txt<br/>no version"];
n5["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>bend<br/><b>not versioned · 1 file</b>"];
n6>"bend_sweep.py<br/>no version"];
n7["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>straight_wg<br/><b>not versioned</b>"];
n0 --> n1
n0 --> n2
n0 --> n3
n0 -.- n4
n0 --> n5
n5 -.- n6
n0 --> n7
classDef project fill:#e4efe9,stroke:#00643c
class n0 project
classDef component fill:#e4efe9,stroke:#00643c
class n5,n7 component
classDef technology fill:#e9f0f8,stroke:#3a6ea5
class n1 technology
classDef library fill:#f0ebf8,stroke:#6b4cc4
class n2 library
classDef source fill:#eef1f3,stroke:#4a5b64
class n3 source
classDef file fill:#fdede6,stroke:#fc7a4c
class n4,n6 file
8. How do I give a component a version?
Section titled “8. How do I give a component a version?”add_version() gives the current save of the component a number and a message. It also
puts the version tag on each file of the component that has no version tag yet. So attach
the files first, then make the version.
The printouts say that the version “labels” a file: it puts the version tag on the file. The tree as text shows the result, before and after. The sweep script changes from “no version” to “1.0.0”.
print(project.tree(target="bend")) # before# also tags the files of the bend that have no version tagproject.add_version("1.0.0", target="bend", message="first bend, radius 3 um")print(project.tree(target="bend")) # afterFAQ project└── component: bend · not versioned · 1 file · radius=3, width=0.5 └── file: bend_sweep.py (no version)FAQ project└── component: bend · 1.0.0 · 1 file · radius=3, width=0.5 └── file: bend_sweep.py (1.0.0)The history now shows one lane for each component and one dot for each version.
project.version_history()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "fontSize": "15px", "tagLabelFontSize": "13px", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}, "gitGraph": {"mainBranchName": "project", "showCommitLabel": false}}}%%
gitGraph
commit id: "FAQ project"
branch bend
commit id: "bend 1.0.0" tag: "1.0.0"
9. How do I give the whole project a version?
Section titled “9. How do I give the whole project a version?”Do not give a target. A project version keeps every component, the technology, the
source and the libraries as they are now. It tags only the files that belong to the
project itself. You can add a project that has a version to another project as a
library, as question 5 adds a PDK.
project.add_version("0.1.0", message="first draft of the FAQ project")project.version_history()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "fontSize": "15px", "tagLabelFontSize": "13px", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}, "gitGraph": {"mainBranchName": "project", "showCommitLabel": false}}}%%
gitGraph
commit id: "FAQ project"
branch bend
commit id: "bend 1.0.0" tag: "1.0.0"
checkout project
commit id: "the project 0.1.0" tag: "0.1.0"
10. How do I keep a DRC rule deck with the technology?
Section titled “10. How do I keep a DRC rule deck with the technology?”A rule deck belongs to the process, not to one component. So keep the deck with the
technology: use the name of the technology as the target. Then give the technology a
version, as question 8 does for a component. The deck gets the version tag of that
version.
Our components use the demo stack of PhotonForge, “Basic Technology”. Its deck,
misc/basic_technology.drc, is a KLayout DRC script. It checks the minimum width and
spacing of the waveguide core, the slab width, the metal width, and the distance from
metal to waveguide core.
tech_name = pf.config.default_technology.name # "Basic Technology"# the deck belongs to the technologyproject.attach("misc/basic_technology.drc", target=tech_name, tags=["drc"])# the version also tags the deckproject.add_version( "1.0.0", target=tech_name, message="demo stack and its first DRC deck")project.version_history("Basic Technology")The fab changes a rule: the minimum core width changes from 0.18 µm to 0.2 µm. A file
does not change after you attach it. So the new deck is a new file, and the technology
gets a new version. The old deck stays, with the version tag version:1.0.0. Use it to
check a component that was taped out with that deck.
# Watch out: attach the new deck BEFORE you make the new version.# If not, the deck has no version tag.project.attach("misc/basic_technology_v2.drc", target=tech_name, tags=["drc"])project.add_version( "1.1.0", target=tech_name, message="core width rule 0.18 -> 0.2 um")
project.tree(target=tech_name) # the technology and its two decks%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}}}%%
flowchart TB
n0(["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>PROJECT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>FAQ project"]);
n1["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>TECHNOLOGY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>Basic Technology<br/>1.1.0 · 2 files"];
n2>"basic_technology_v2.drc<br/>1.1.0"];
n3>"basic_technology.drc<br/>1.0.0"];
n0 --> n1
n1 -.- n2
n1 -.- n3
classDef project fill:#e4efe9,stroke:#00643c
class n0 project
classDef technology fill:#e9f0f8,stroke:#3a6ea5
class n1 technology
classDef file fill:#fdede6,stroke:#fc7a4c
class n2,n3 file
To run the deck of one version, find the deck by its tags and download it. Then run KLayout on your GDS file:
# the deck of version 1.1.0deck = project.attachments(target=tech_name, tags=["drc", "version:1.1.0"])[0]Path("drc_rules.drc").write_bytes(project.download_attachment(deck))print("downloaded", deck["filename"], "as drc_rules.drc")# Then, in a terminal:# klayout -b -r drc_rules.drc -rd input=chip.gds -rd report=drc.lyrdbdownloaded basic_technology_v2.drc as drc_rules.drcC. Work with your team
Section titled “C. Work with your team”11. How do I share the project?
Section titled “11. How do I share the project?”
To share with one colleague, you need their user id, not their email address. The
colleague runs pda.user_info() and sends you the id. To share with your whole
organization, you need no id. The roles are viewer (read only) and editor.
my_user_id, my_org_id = pda.user_info()print("my user id:", my_user_id)
# To share with one colleague:# project.grant_permission(# visibility="private", grantee_id="<their user id>", role="editor"# )# To share with your whole organization:# project.grant_permission(visibility="organization", role="viewer")
for p in project.list_permissions(): # who can open the project now: only you print(p["role"], p["visibility"], p["granteeId"])my user id: user-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxowner private user-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx12. How do I know that a colleague changed a component?
Section titled “12. How do I know that a colleague changed a component?”Take a marker with latest_head(). Later, changed_since(marker) lists each save after
the marker. To get a message at the time of a save, use watch(). It runs a function of
yours for each save.
Here the colleague is a real second Python program, as on a different computer
(run_colleague() from the setup). It opens the project and saves the bend two times,
each time with a larger width. This notebook watches.
marker = project.latest_head("bend") # where the bend is nowtold = [] # the times at which we get a message
def tell_me(changes): """Runs in the background for each save to the bend. Keep it short.""" told.append(time.time())
# start to watch the bend, then let the colleague save two timeswatcher = project.watch("bend", on_change=tell_me, fields="parameters")saved = run_colleague(project.id, "bend", "width=0.7", "width=0.9")time.sleep(3)watcher.cancel() # stop the watcher
for saved_at, told_at in zip(saved, told): print(f"the colleague saved; we were told {told_at - saved_at:.1f} s later")the colleague saved; we were told 2.9 s laterthe colleague saved; we were told 2.3 s laterThe marker finds each save after it, also the saves that nobody watched.
fields="parameters" counts only changes to the parameters of the PCell.
project.changed_since(marker, fields="parameters")| save | session | field | change | note |
|---|---|---|---|---|
| 2 | 6d01 | width | 0.5 (default) -> 0.7 | |
| 3 | 6d01 | width | 0.7 -> 0.9 |
project.load_latest(), then look before you save13. How do I see every save?
Section titled “13. How do I see every save?”edit_log() lists every save, oldest first. It also shows the values that later saves
wrote over. It tells what changed and in which sequence. It does not tell who saved or
when: a “session” is one run of Python, not a person.
project.edit_log("bend", fields="parameters")| save | session | field | change | note |
|---|---|---|---|---|
| 1 | 1267 | parameters | set to {} | |
| 2 | 6d01 | width | 0.5 (default) -> 0.7 | |
| 3 | 6d01 | width | 0.7 -> 0.9 |
project.component("bend", save=<n>) rebuilds it as it was after save n14. What if two people change the same parameter?
Section titled “14. What if two people change the same parameter?”Alice sets the bend radius to 5 µm. Bob works on an older copy and sets the radius to
10 µm. The last save wins, and the save gives no warning. But nothing is lost. Alice’s
5.0 stays in the edit log, and Bob can see her save with changed_since() or
edit_log().

In this example, this notebook is Bob. Alice is the second program again.
project.load_latest() # Bob gets the latest saves of everyonemarker = project.latest_head("bend") # and takes a markerbobs_copy = project.component("bend")
run_colleague(project.id, "bend", "radius=5.0") # Alice saves radius 5.0
bobs_copy.update(radius=10.0) # Bob sets 10.0 on his older copyproject.update(bobs_copy) # and saves: the last save wins, with no warningtime.sleep(3)
project.changed_since(marker, fields="parameters") # both saves are in the log| save | session | field | change | note |
|---|---|---|---|---|
| 4 | db30 | radius | 3.0 (default) -> 5.0 | |
| 5 | 1267 | radius | 5.0 -> 10.0 |
project.load_latest(), then look before you saveYou can rebuild each save with component(name, save=...). These two lines show what
each save left:
# the two saves after the markeralices, bobs = project.changed_since(marker, fields="parameters")print("after Alice's save:", project.component("bend", save=alices).parametric_kwargs)print("after Bob's save :", project.component("bend", save=bobs).parametric_kwargs)after Alice's save: {'radius': 5.0, 'width': 0.9}after Bob's save : {'radius': 10.0, 'width': 0.9}To prevent this, look for new saves immediately before you save:
if project.changed_since(marker, fields="parameters"): print("someone saved after you looked: call load_latest(), then look again")Also, update() saves your whole copy. If your copy is old, update() also writes back
the old values that you did not change. So call load_latest() before you edit.
D. Go back to an earlier state
Section titled “D. Go back to an earlier state”15. How do I go back to a version?
Section titled “15. How do I go back to a version?”Rebuild the component as it was at that version. Then save it as the current component. The later saves stay in the edit log. Nothing is deleted.
project.load_latest() # the latest saves of everyonenow = project.component("bend")back = project.component("bend", version="1.0.0") # the bend at version 1.0.0compare(("now", now), ("at version 1.0.0", back)) # the two bends, same scaleproject.update(back) # save the bend of version 1.0.0 as the current bendtime.sleep(3)# Watch out: give a version only to what is on the server. Here our copy is# current, because we saved it above. If not, call project.load_latest() first.project.add_version("1.1.0", target="bend", message="back to the 1.0.0 bend")print("the bend now:", project.component("bend").parametric_kwargs)the bend now: {'radius': 3.0, 'width': 0.5}Call load_latest() before you give something a version. Then the version is of what is
on the server.
16. How do I see a component at any save?
Section titled “16. How do I see a component at any save?”You can rebuild any save with component(name, save=...), with or without a version.
Here are the bends that Alice and Bob saved in question 14. Neither save has a version:
compare(("Alice's save", project.component("bend", save=alices)), ("Bob's save", project.component("bend", save=bobs)))E. See the whole project
Section titled “E. See the whole project”17. What is “the latest” bend?
Section titled “17. What is “the latest” bend?”There are two meanings, and they can be different:
- the latest saves of everyone:
load_latest(), thencomponent("bend"), - the newest version: the newest entry in
version_history().
project.load_latest()print("the latest saves :", project.component("bend").parametric_kwargs)
# the number of the newest versionnewest = project.version_history("bend", kinds=["version"], limit=1)[0].labelprint(f"version {newest} :", project.component("bend", version=newest).parametric_kwargs)the latest saves : {'radius': 3.0, 'width': 0.5}version 1.1.0 : {'radius': 3.0, 'width': 0.5}18. How do I keep measurements, and get the files of one version?
Section titled “18. How do I keep measurements, and get the files of one version?”Attach the measurement data to the component that you measured. In its tags, write the version of the chip that you measured. A file with no version tag gets the next version that you make. That version can be different from the chip that you measured.
# Watch out: without "version:1.0.0" here, the next add_version() gives# this file the wrong version tag.project.attach( "misc/bend_loss.csv", target="bend", tags=["measurement", "version:1.0.0"])
# Download all files of version 1.0.0folder = Path("downloads/bend-1.0.0")folder.mkdir(parents=True, exist_ok=True)for f in project.attachments(target="bend", tags=["version:1.0.0"]): (folder / f["filename"]).write_bytes(project.download_attachment(f)) print("downloaded", f["filename"])downloaded bend_loss.csvdownloaded bend_sweep.pytraceability_matrix() shows which file belongs to which version. ✓ is the version that
a file belongs to. · is a version of its component or technology that the file does not
belong to.
project.traceability_matrix()| file | target | 0.1.0 | 1.0.0 | 1.1.0 | note |
|---|---|---|---|---|---|
| design_review.txt | the project | ✓ | |||
| bend_loss.csv | bend | ✓ | · | ||
| bend_sweep.py | bend | ✓ | · | ||
| basic_technology_v2.drc | Basic Technology | · | ✓ | ||
| basic_technology.drc | Basic Technology | ✓ | · |
project.trace(<file>) rebuilds the component a file belongs to19. How do I see the whole history?
Section titled “19. How do I see the whole history?”version_history() draws all the versions. .table() gives the same history as a table,
with dates and messages. .mermaid() gives the source of the drawing, which you can paste
into a wiki or a Markdown page.
project.version_history()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "fontSize": "15px", "tagLabelFontSize": "13px", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}, "gitGraph": {"mainBranchName": "project", "showCommitLabel": false}}}%%
gitGraph
commit id: "FAQ project"
branch bend
commit id: "bend 1.0.0" tag: "1.0.0"
checkout project
commit id: "the project 0.1.0" tag: "0.1.0"
branch Basic_Technology
commit id: "Basic Technology 1.0.0" tag: "1.0.0"
commit id: "Basic Technology 1.1.0" tag: "1.1.0"
checkout bend
commit id: "bend 1.1.0" tag: "1.1.0"
project.version_history().table()| when | target | version | message | files labelled | by |
|---|---|---|---|---|---|
| 06 Nov 2026 14:02 (1 min ago) | bend | 1.1.0 | back to the 1.0.0 bend | - | you |
| 06 Nov 2026 14:01 (1 min ago) | Basic Technology | 1.1.0 | core width rule 0.18 -> 0.2 um | basic_technology_v2.drc | you |
| 06 Nov 2026 14:01 (1 min ago) | Basic Technology | 1.0.0 | demo stack and its first DRC deck | basic_technology.drc | you |
| 06 Nov 2026 14:01 (1 min ago) | the project | 0.1.0 | first draft of the FAQ project | design_review.txt | you |
| 06 Nov 2026 14:01 (1 min ago) | bend | 1.0.0 | first bend, radius 3 um | bend_loss.csv, bend_sweep.py | you |
project.load("bend", version="1.1.0") rebuilds a version20. How do I see everything in the project at one time?
Section titled “20. How do I see everything in the project at one time?”tree() shows the technology with its DRC decks, the library, the source, each component
with its newest version, and each file with the version that it belongs to.
project.tree()%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}}}%%
flowchart TB
n0(["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>PROJECT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>FAQ project"]);
n1["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>TECHNOLOGY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>Basic Technology<br/>1.1.0 · 2 files"];
n2>"basic_technology_v2.drc<br/>1.1.0"];
n3>"basic_technology.drc<br/>1.0.0"];
n4("<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>LIBRARY</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>SiEPIC EBeam");
n5[["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>SOURCE</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>1 file<br/>waveguide_bend.py"]];
n6>"design_review.txt<br/>0.1.0"];
n7["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>bend<br/><b>1.1.0 · 2 files</b>"];
n8>"bend_loss.csv<br/>1.0.0"];
n9>"bend_sweep.py<br/>1.0.0"];
n10["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>straight_wg<br/><b>not versioned</b>"];
n0 --> n1
n1 -.- n2
n1 -.- n3
n0 --> n4
n0 --> n5
n0 -.- n6
n0 --> n7
n7 -.- n8
n7 -.- n9
n0 --> n10
classDef project fill:#e4efe9,stroke:#00643c
class n0 project
classDef component fill:#e4efe9,stroke:#00643c
class n7,n10 component
classDef technology fill:#e9f0f8,stroke:#3a6ea5
class n1 technology
classDef library fill:#f0ebf8,stroke:#6b4cc4
class n4 library
classDef source fill:#eef1f3,stroke:#4a5b64
class n5 source
classDef file fill:#fdede6,stroke:#fc7a4c
class n2,n3,n6,n8,n9 file
The same tree as text. You can search it, copy it, or paste it into an email:
print(project.tree())FAQ project├── technology: Basic Technology · 1.1.0 · 2 files│ ├── file: basic_technology_v2.drc (1.1.0)│ └── file: basic_technology.drc (1.0.0)├── library: SiEPIC EBeam├── source: 1 file (waveguide_bend.py)├── file: design_review.txt (0.1.0)├── component: bend · 1.1.0 · 2 files│ ├── file: bend_loss.csv (1.0.0)│ └── file: bend_sweep.py (1.0.0)└── component: straight_wg · not versionedIn a large project, the tree shows the files and the cells of a component as one row, for
example “9 cells”. The row gives the call that lists them. To see all of one component,
use target:
project.tree(target="bend")%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#e4efe9", "primaryBorderColor": "#00643c", "primaryTextColor": "#13231b", "lineColor": "#4a5b54", "tagLabelColor": "#13231b", "tagLabelBackground": "#ffffff", "tagLabelBorder": "#00643c", "commitLabelColor": "#13231b", "commitLabelBackground": "#ffffff", "git0": "#00643c", "gitBranchLabel0": "#ffffff", "gitInv0": "#00643c", "git1": "#6b4cc4", "gitBranchLabel1": "#ffffff", "gitInv1": "#6b4cc4", "git2": "#b3541e", "gitBranchLabel2": "#ffffff", "gitInv2": "#b3541e", "git3": "#1f6f8b", "gitBranchLabel3": "#ffffff", "gitInv3": "#1f6f8b", "git4": "#8a5209", "gitBranchLabel4": "#ffffff", "gitInv4": "#8a5209", "git5": "#7a3e9d", "gitBranchLabel5": "#ffffff", "gitInv5": "#7a3e9d", "git6": "#2f6b3f", "gitBranchLabel6": "#ffffff", "gitInv6": "#2f6b3f", "git7": "#a03d5f", "gitBranchLabel7": "#ffffff", "gitInv7": "#a03d5f"}}}%%
flowchart TB
n0(["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>PROJECT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>FAQ project"]);
n1["<span style='font-size:0.78em;letter-spacing:0.04em;color:#4a5b54'>COMPONENT</span><hr style='margin:3px 0;border:0;border-top:1px solid #4a5b54'/>bend<br/><b>1.1.0 · 2 files · radius=3, width=0.5</b>"];
n2>"bend_loss.csv<br/>1.0.0"];
n3>"bend_sweep.py<br/>1.0.0"];
n0 --> n1
n1 -.- n2
n1 -.- n3
classDef project fill:#e4efe9,stroke:#00643c
class n0 project
classDef component fill:#e4efe9,stroke:#00643c
class n1 component
classDef file fill:#fdede6,stroke:#fc7a4c
class n2,n3 file
Watch out: a summary
Section titled “Watch out: a summary”- The server gets each save immediately.
add()andupdate()are the saves. There is no separate upload step. add()returns a moment before the server has the component. Wait a moment before you read the component back.add()works one time for each name. Useupdate()for later changes.- Each component needs its own name. A PCell must give each variant a name that it makes from its parameters.
- Attach the files first, then make the version.
add_version()tags each file that has no version tag. - Give measurement data the version tag of the chip that you measured, for example
version:1.0.0. If not, the file gets the next version that you make. update()saves your whole copy. An old copy writes back values that you did not change. Callload_latest()before you edit.- The last save wins, with no warning. Look at
changed_since(marker)before you save. - Call
load_latest()before you make a version, so that the version is of what is on the server. add_module_file()stops with an error if the project code changed after you opened the project. Callload_latest()first.import_module(globals())adds a module with the name of each project, for examplefaq_project. If you have a variable with the same name, the module replaces it.- Open a project with its id. A search by name opens every project that you can see, so it is slow. Find a library by its name one time, and keep its id.
- A file does not change after you attach it. For a new edition of a file, attach a new file, with a tag that tells the two files apart.
- A change to the project code counts only after you save it, as for a component.
add_module_file()saves a new file.save_module()saves changed and deleted files. The tree shows unsaved changes in orange. - A
targetis a component, a technology, or nothing. Use the name or the object. A placed reference is not a target: usereference.component.
When you are done
Section titled “When you are done”Each run of this notebook makes a new project in your account. To remove the project, retire it:
pda.retire_project(project_id=project.id)To bring it back, use pda.restore_project(project_id=...).