Copying Objects

PlexosDB allows you to create copies of existing objects along with their properties, memberships, and associated data.

Basic Object Copying

Copy an object and all its properties:

from plexosdb import PlexosDB
from plexosdb.enums import ClassEnum

# Initialize database
db = PlexosDB.from_xml("/path/to/model.xml")

db.add_property(
    ClassEnum.Generator,
    object_name="Generator1",
    name="Max Capacity",
    value=100.0,
    scenario="Base Case"
)

db.add_property(
    ClassEnum.Generator,
    object_name="Generator1",
    name="Min Stable Level",
    value=20.0,
    scenario="Base Case"
)

# Copy a generator with all its properties
new_object_id = db.copy_object(
    object_class=ClassEnum.Generator,
    original_object_name="Generator1",
    new_object_name="Generator1_Copy",
    copy_properties=True  # Default is True
)

print(f"Created new object with ID: {new_object_id}")

Copying Objects Without Properties

You can also copy just the object structure without its properties:

# Add Generator object
db.add_object(ClassEnum.Generator, "Generator1")

# Add property
db.add_property(
    ClassEnum.Generator,
    object_name="Generator1",
    name="Max Capacity",
    value=20.0,
    scenario="Base Case"
)

# Copy object structure only
new_object_id = db.copy_object(
    object_class=ClassEnum.Generator,
    original_object_name="Generator1",
    new_object_name="Generator1_Skeleton",
    copy_properties=False
)

Copying Memberships

When copying an object, its memberships are also copied:

# First create some objects with memberships
db.add_object(ClassEnum.Region, "Region1")
db.add_object(ClassEnum.Node, "Node1")

# Add membership
db.add_membership(
    parent_class_enum=ClassEnum.Region,
    child_class_enum=ClassEnum.Node,
    parent_object_name="Region1",
    child_object_name="Node1",
    collection_enum=CollectionEnum.ReferenceNode
)

# Add property
db.add_property(
    ClassEnum.Node,
    object_name="Node1",
    name="Voltage",  # Common node property
    value=138.0,
    scenario="Base Case"
)

# Now copy the node with its memberships
new_object_id = db.copy_object(
    object_class=ClassEnum.Node,
    original_object_name="Node1",
    new_object_name="Node1_Copy",
    copy_properties=False
)

# Check the memberships of the new object
memberships = db.get_memberships_system(
    "Node1_Copy",
    object_class=ClassEnum.Node
)
print(f"New object has {len(memberships)} memberships")

Selective Membership Copying

You can also manually copy specific memberships:

db.add_object(ClassEnum.Node, "Node1")
db.add_object(ClassEnum.Generator, "Generator1")

db.add_membership(
    parent_class_enum=ClassEnum.Generator,
    child_class_enum=ClassEnum.Node,
    parent_object_name="Generator1",
    child_object_name="Node1",
    collection_enum=CollectionEnum.Nodes
)

membership_mapping = db.copy_object_memberships(
    object_class=ClassEnum.Generator,
    original_name="Generator1",
    new_name="Generator1_Copy"
)

print(f"Copied {len(membership_mapping)} memberships")

Practical Example: Duplicating a Set of Objects

This example shows how to duplicate a group of related objects:

# Create a function to copy a generator and all its connections
def duplicate_generator_with_connections(db, original_name, new_name):
    # Add Generator object
    db.add_object(ClassEnum.Generator, original_name)

    # Add Generator property
    db.add_property(
        ClassEnum.Generator,
        object_name=original_name,
        name="Max Capacity",  # Common node property
        value=138.0,
        scenario="Base Case"
    )

    # Copy the generator itself
    db.copy_object(
        object_class=ClassEnum.Generator,
        original_object_name=original_name,
        new_object_name=new_name,
        copy_properties=False
    )

    # Find and copy all connections
    memberships = db.get_memberships_system(
        original_name,
        object_class=ClassEnum.Generator
    )

    # Process each membership to maintain the network structure
    for membership in memberships:
        # Skip system memberships which are automatically created
        if membership["parent_class_name"] == "System":
            continue

        if membership["parent"] == original_name:
            # Original generator was the parent, connect child to new generator
            db.add_membership(
                parent_class_enum=ClassEnum[membership["parent_class_name"]],
                child_class_enum=ClassEnum[membership["child_class_name"]],
                parent_object_name=new_name,
                child_object_name=membership["child"],
                collection_enum=CollectionEnum[membership["collection_name"]]
            )
        else:
            # Original generator was the child, connect new generator to parent
            db.add_membership(
                parent_class_enum=ClassEnum[membership["parent_class_name"]],
                child_class_enum=ClassEnum[membership["child_class_name"]],
                parent_object_name=membership["parent"],
                child_object_name=new_name,
                collection_enum=CollectionEnum[membership["collection_name"]]
            )

    return new_name

# Use the function to duplicate a generator with all its connections
duplicate_generator_with_connections(db, "Generator1", "Generator1_Full_Copy")

Note

When copying objects with properties that reference other objects (like “Node” for a generator), you may need to update these properties manually if you want them to reference different objects.