diff --git a/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py b/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py index 1eae029413..799ef05d00 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py +++ b/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py @@ -18,7 +18,7 @@ class Usecase: - def __init__(self, file, classifcation=None): + def __init__(self, file, classification=None): """Removes an IfcClassification from the project and all references The classification and all of its relationships, children references, @@ -36,7 +36,6 @@ class Usecase: ifcopenshell.api.run("classification.remove_classification", model, classification=classification) """ - self.file = file self.settings = {"classification": classification} diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item.py b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item.py index dd5ea27fab..76e3b95d5e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item.py @@ -20,11 +20,36 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_schedule=None, cost_item=None): + """Add a new cost item + + A cost item represents a single line item in a cost schedule. Cost items + may then be broken down into cost subitems. + + :param cost_schedule: If the cost item is to be added as a root or top + level cost item to a cost schedule, the IfcCostSchedule may be + specified. This is mutually exlclusive to the cost_item parameter. + :type cost_schedule: ifcopenshell.entity_instance.entity_instance + :param cost_item: If the cost item is to be added as a subitem to an + existing cost item, the parent IfcCostItem may be specified. This is + mutually exclusive to the cost_schedule parameter. + :type cost_item: ifcopenshell.entity_instance.entity_instance + :return: The newly created IfcCostItem + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # The very first cost item must be in a cost schedule + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + + # You may add cost items as top level item in the schedule + item1 = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # Alternatively you may add them as subitems + item2 = ifcopenshell.api.run("cost.add_cost_item", model, cost_item=item1) + """ self.file = file - self.settings = {"cost_schedule": None, "cost_item": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_schedule": cost_schedule, "cost_item": cost_item} def execute(self): cost_item = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcCostItem") diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py index 461be656b4..1af6266612 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py @@ -20,11 +20,58 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None, ifc_class="IfcQuantityCount"): + """Adds a new quantity associated with a cost item + + Cost items calculate their subtotal by multiplying the sum of the cost + item's "values" by the sum of the cost item's "quantities". The + quantities may be either parametrically linked to quantities measured on + physical product, or manually specified. + + The quantity must be of a particular type, common examples are: + + - IfcQuantityCount: to count the total occurrences of a product, useful + for things like doors, windows, and furniture + - IfcQuantityNumber: any other generic numeric quantity + - IfcQuantityLength + - IfcQuantityArea + - IfcQuantityVolume + - IfcQuantityWeight + - IfcQuantityTime + + A cost item must not mix quantities of different types. + + If an IfcQuantityCount is used, then this API will automatically count + all products that this cost item controls (see + ifcopenshell.api.controls.assign_control) and prefill that quantity. + + For all other quantity types, the quantity is left as zero and the user + must either manually specify the quantity or parametrically link it + using another API call. + + :param cost_item: The IfcCostItem to add the quantity to + :type cost_item: ifcopenshell.entity_instance.entity_instance + :param ifc_class: The type of quantity to add + :type ifc_class: str, optional + :return: The newly created quantity entity, chosen from the ifc_class + parameter + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + chair = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurniture") + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + ifcopenshell.api.run("control.assign_control", model, + relating_control=cost_item, related_object=chair) + + # Let's assume we want to count the amount of chairs to calculate our cost item + # Because this is an IfcQuantityCount the count will be automatically set to "1" chair + ifcopenshell.api.run("cost.add_cost_item_quantity", model, + cost_item=item, ifc_class="IfcQuantityCount") + """ self.file = file - self.settings = {"cost_item": None, "ifc_class": "IfcQuantityCount"} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item, "ifc_class": ifc_class} def execute(self): quantity = self.file.create_entity(self.settings["ifc_class"], Name="Unnamed") diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py index cd96028ef2..cdd2eeb798 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py @@ -22,11 +22,37 @@ from datetime import datetime class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, name=None, predefined_type="NOTDEFINED"): + """Add a new cost schedule + + A cost schedule is a group of cost items which typically represent a + cost plan or breakdown of the project. This may be used as an estimate, + bid, or actual cost. + + Alternatively, a cost schedule may also represent a schedule of rates, + which include cost items which capture unit rates for different elements + or processes. + + As such, creating a cost schedule is necessary prior to creating and + managing any cost items. + + :param name: The name of the cost schedule. + :type name: str, optional + :param predefined_type: The predefined type of the cost schedule, chosen + from a valid type in the IFC documentation for + IfcCostScheduleTypeEnum + :type predefined_type: str, optional + :return: The newly created IfcCostSchedule entity + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + # Now that we have a cost schedule, we may add cost items to it + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + """ self.file = file - self.settings = {"name": None, "predefined_type": "NOTDEFINED", "start_time": datetime.now()} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"name": name, "predefined_type": predefined_type} def execute(self): cost_schedule = ifcopenshell.api.run( diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py index 4cdc58af30..9163685cfc 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py @@ -18,11 +18,79 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, parent=None): + """Adds a new value or subvalue to a cost item + + A cost item's subtotal can be specified in two ways. + + Option 1 is by simply manually specifying the subtotal value, which + represents the full cost of that cost item. This option occurs when a + cost item has no quantities associated with it. + + Option 2 is by specifying a unit cost value of the cost item, which is + then multiplied by the associated quantity of the cost item, to give us + the subtotal. This option occurs when a cost item has quantities + associated with it. + + For either option 1 (full cost value) or option 2 (unit cost value), the + cost value may be specified as a single number, or as a sum of + subcomponents or formulas (e.g. multiplication by wastage factor, or + adding taxes or other adjustments). + + This function lets you add a single top level unit value to a cost item, + or alternatively price subcomponents by using the "parent" parameter. + + More advanced usage, which involves summing, subcategory-filtered costs, + and formulas are possible but not yet documented. + + :param parent: A parent IfcCostItem, if specifying a price directly to a + cost item, or a top-level price component. Alternatively, this can + be set to a IfcCostValue, if specifying price subcomponents. + :type parent: ifcopenshell.entity_instance.entity_instance + :return: The newly created IfcCostValue + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # We always need a schedule first prior to adding any cost items + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + + # Option 1: This cost item will have a full cost of 42.0 + item1 = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item1) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 42.0}) + + # Option 2: This cost item will have a unit cost of 5.0 per unit + # area, multiplied by the quantity of area specified explicitly as + # 3.0, giving us a subtotal cost of 15.0. + item2 = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item2) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 5.0}) + quantity = ifcopenshell.api.run("cost.add_cost_item_quantity", model, + cost_item=item2, ifc_class="IfcQuantityVolume") + ifcopenshell.api.run("cost.edit_cost_item_quantity", model, + physical_quantity=quantity, "attributes": {"VolumeValue": 3.0}) + + # A cost value may also be specified in terms of the sum of its + # subcomponents. In this case, it's broken down into 2 subvalues. + item1 = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item1) + subvalue1 = ifcopenshell.api.run("cost.add_cost_value", model, parent=value) + subvalue2 = ifcopenshell.api.run("cost.add_cost_value", model, parent=value) + + # This specifies that the value is the sum of all subitems + # regardless of their cost category. The first subvalue is 2.0 and + # the second is 3.0, giving a total value of 5.0. + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, attributes={"Category": "*"}) + ifcopenshell.api.run("cost.edit_cost_value", model, + cost_value=subvalue1, attributes={"AppliedValue": 2.0}) + ifcopenshell.api.run("cost.edit_cost_value", model, + cost_value=subvalue2, attributes={"AppliedValue": 3.0}) + """ self.file = file - self.settings = {"parent": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"parent": parent} def execute(self): value = self.file.create_entity("IfcCostValue") diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_item_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_item_quantity.py index 80e2301b6a..1114691961 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_item_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_item_quantity.py @@ -20,11 +20,62 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None, products=None, prop_name=""): + """Adds a cost item quantity that is parametrically connected to a product + + A cost item may have its subtotal calculated by multiplying a unit value + by a quantity associated with the cost item. That quantity may be either + manually specified or parametrically connected to a quantity on a + product. This API function lets you create that parametric connection. + + For example, you may wish to have a cost item linked to the "NetVolume" + quantity on all IfcSlabs. Each quantity has a name which you can + specify. If the quantity is updated in-place (which should occur for + Native IFC applications) then the quantity for the cost item will + automatically update as well. If the quantity is deleted and then + re-added, then the parametric relationship is also lost. + + This API also automatically assigns a control relationship between the + cost item and the product, so it is not necessary to use + ifcopenshell.api.control.assign_control. + + :param cost_item: The IfcCostItem to assign parametric quantities to + :type cost_item: ifcopenshell.entity_instance.entity_instance + :param products: The IfcObjects to assign parametric quantities to + :type products: list[ifcopenshell.entity_instance.entity_instance] + :param prop_name: The name of the quantity. If this is not specified, + then it is assumed that there is no calculated quantity, and the + number of objects are counted instead. + :type prop_name: str, optional + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # Let's imagine a unit cost of 5.0 per unit volume + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 5.0}) + + slab = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSlab") + # Usually the quantity would be automatically calculated via a + # graphical authoring application but let's assign a manual quantity + # for now. + qto = ifcopenshell.api.run("pset.add_qto", model, product=slab, name="Qto_SlabBaseQuantities") + ifcopenshell.api.run("pset.edit_qto", model, qto=qto, properties={"NetVolume": 42.0}) + + # Now let's parametrically link the slab's quantity to the cost + # item. If the slab is edited in the future and 42.0 changes, then + # the updated value will also automatically be applied to the cost + # item. + ifcopenshell.api.run("cost.assign_cost_item_quantity", model, + cost_item=item, products=[slab], prop_name="NetVolume") + """ self.file = file - self.settings = {"cost_item": None, "products": [], "prop_name": ""} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item, "products": products or [], "prop_name": prop_name} def execute(self): if self.settings["prop_name"]: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py index 5193e2e2e0..74d0c79e00 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py @@ -20,11 +20,46 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None, cost_rate=None): + """Assigns a cost value to a cost item from a schedule of rates + + Instead of assigning cost values from scratch for each cost item in a + cost schedule, the cost values may instead be assigned from a schedule + of rates. + + A schedule of rates is just another cost schedule which have cost values + but no quantities. This API will allow you to "copy" the values from a + cost item in the schedule of rates into another cost item in your own + cost schedule. When the schedule of rates value is updated, then your + cost item values will also be updated. You can think of the schedule of + rates as a "template" to quickly populate your rates from. + + :param cost_item: The IfcCostItem that you want to copy the values to + :type cost_item: ifcopenshell.entity_instance.entity_instance + :param cost_rate: The IfcCostItem that you want to copy the values from + :type cost_rate: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + # Let's create a schedule of rates with a single rate in it of 5.0 + rate_tables = ifcopenshell.api.run("cost.add_cost_schedule", model, + predefined_type="SCHEDULEOFRATES") + rate = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 5.0}) + + # And this schedule will be for our actual cost plan / estimate / etc + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # Now the cost item has the same rate as the one from the schedule of rate's item + ifcopenshell.api.run("cost.assign_cost_value", model, cost_item=item, cost_rate=rate) + """ self.file = file - self.settings = {"cost_item": None, "cost_rate": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item, "cost_rate": cost_rate} def execute(self): for cost_value in self.settings["cost_item"].CostValues: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py index 36a151f7b2..fc7021304f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py @@ -21,11 +21,68 @@ import ifcopenshell.util.date class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None): + """Calculates the total cost of all resources associated with a cost item + + A cost item may have construction resources (e.g. equipment, material, + etc) assigned to it. Construction resources may be assigned directly to + the cost item, or assigned first to a task, and the task is then + assigned to the cost item. + + The cost of a resource is calculated by the total sum of all of its base + costs. If no quantity is provided, that sum is considered to be the + total cost. Otherwise, it is considered to be a unit cost, and is then + multiplied by the resource quantity. The quantity is either stored as a + base quantity (such as a volume) for a things like material resources, + or as a duration as a daily rate for labour resources. + + The final calculated cost is set as the cost item's value. Any + previously existing values are removed. + + :param cost_item: The IfcCostItem to calculate + :type cost_item: ifccopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + # First, we need a cost schedule and item + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # Let's imagine we have our own formworking crew + crew = ifcopenshell.api.run("resource.add_resource", model, ifc_class="IfcCrewResource") + + # ... and they need concrete + concrete = ifcopenshell.api.run("resource.add_resource", model, + ifc_class="IfcConstructionMaterialResource", parent_resource=crew) + ifcopenshell.api.run("control.assign_control", model, + relating_control=item, related_object=concrete) + # ... which has a unit price of 42.0 per m3 + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=concrete) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 42.0}) + # ... and a volume of 200m3 + quantity = ifcopenshell.api.run("resource.add_resource_quantity", model, + resource=concrete, ifc_class="IfcQuantityVolume") + ifcopenshell.api.run("resource.edit_resource_quantity", model, + physical_quantity=quantity, "attributes": {"VolumeValue": 200.0}) + + # Let's say they also need some equipment + equipment = ifcopenshell.api.run("resource.add_resource", model, + ifc_class="IfcConstructionEquipmentResource", parent_resource=crew) + ifcopenshell.api.run("control.assign_control", model, + relating_control=item, related_object=equipment) + # ... with a fixed price of 50,000 + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=concrete) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 42.0}) + + # (42 * 200) + 50000 = 58400 is our calculated cost + ifcopenshell.api.run("cost.calculate_cost_item_resource_value", model, cost_item=item) + """ self.file = file - self.settings = {"cost_item": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item} def execute(self): for cost_value in self.settings["cost_item"].CostValues or []: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/copy_cost_item_values.py b/src/ifcopenshell-python/ifcopenshell/api/cost/copy_cost_item_values.py index 6b9b0a3f99..338b66e386 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/copy_cost_item_values.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/copy_cost_item_values.py @@ -20,11 +20,37 @@ import ifcopenshell.util.element class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, source=None, destination=None): + """Copies all cost values from one cost item to another + + Any previously existing values will be removed. The entire value is + copied, including all components and formulas. However they are not + parametrically linked, so if one value changes, the other will not. + + :param source: The IfcCostItem to copy cost values from + :type source: ifcopenshell.entity_instance.entity_instance + :param destination: The IfcCostItem to copy cost values from + :type destination: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + # Assume we have a schedule with multiple items in it + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item1 = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + item2 = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # One of the items has a value + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 5000.0}) + + # Let's copy the value from one item to another + ifcopenshell.api.run("cost.copy_cost_item_values", model, source=item1, destination=item2) + """ self.file = file - self.settings = {"source": None, "destination": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"source": source, "destination": destination} def execute(self): for cost_value in self.settings["destination"].CostValues or []: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item.py b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item.py index 69c5d4216e..29d76dc5f9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item.py @@ -18,11 +18,27 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None, attributes=None): + """Edits the attributes of an IfcCostItem + + For more information about the attributes and data types of an + IfcCostItem, consult the IFC documentation. + + :param cost_item: The IfcCostItem entity you want to edit + :type cost_item: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + ifcopenshell.api.run("cost.edit_cost_item", model, cost_item=item, attributes={"Name": "Foo"}) + """ self.file = file - self.settings = {"cost_item": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item_quantity.py index ff13240f43..9cc676676f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_item_quantity.py @@ -18,11 +18,35 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, physical_quantity=None, attributes=None): + """Edits the attributes of an IfcPhysicalQuantity + + For more information about the attributes and data types of an + IfcPhysicalQuantity, consult the IFC documentation. + + :param physical_quantity: The IfcPhysicalQuantity entity you want to edit + :type physical_quantity: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # This cost item will have a unit cost of 5 and a volume of 3 + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 5.0}) + quantity = ifcopenshell.api.run("cost.add_cost_item_quantity", model, + cost_item=item, ifc_class="IfcQuantityVolume") + ifcopenshell.api.run("cost.edit_cost_item_quantity", model, + physical_quantity=quantity, "attributes": {"VolumeValue": 3.0}) + """ self.file = file - self.settings = {"physical_quantity": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"physical_quantity": physical_quantity, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_schedule.py index dce8341528..627946a657 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_schedule.py @@ -18,11 +18,28 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_schedule=None, attributes=None): + """Edits the attributes of an IfcCostSchedule + + For more information about the attributes and data types of an + IfcCostSchedule, consult the IFC documentation. + + :param cost_schedule: The IfcCostSchedule entity you want to edit + :type cost_schedule: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + ifcopenshell.api.run("cost.edit_cost_schedule", model, + cost_schedule=schedule, attributes={"Name": "Foo"}) + """ + self.file = file - self.settings = {"cost_schedule": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_schedule": cost_schedule, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value.py index 005c780f99..75b186f303 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value.py @@ -22,11 +22,31 @@ import ifcopenshell.util.element class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_value=None, attributes=None): + """Edits the attributes of an IfcCostValue + + For more information about the attributes and data types of an + IfcCostValue, consult the IFC documentation. + + :param cost_value: The IfcCostValue entity you want to edit + :type cost_value: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # This cost item will have a total cost of 42 + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 42.0}) + """ self.file = file - self.settings = {"cost_value": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_value": cost_value, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value_formula.py b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value_formula.py index 1a69cb4bbd..d855d50fdd 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value_formula.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/edit_cost_value_formula.py @@ -23,11 +23,33 @@ import ifcopenshell.util.element class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_value=None, formula=None): + """Sets a cost value based on a formula, similar to formulas in spreadsheets + + Costs may be made up of many components (e.g. labour, material, waste + factor, taxes, etc). This can be easily represented in the form of a + formula similar thta would be used in spreadsheet applications. + + For more information, see ifcopenshell.util.cost + + :param cost_value: The IfcCostValue to set the values of + :type cost_value: ifcopenshell.entity_instance.entity_instance + :param formula: The formula following the language of ifcopenshell.util.cost + :type formula: str + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value_formula", model, cost_value=value, + formula="5000 * 1.19") + """ self.file = file - self.settings = {"cost_value": None, "formula": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_value": cost_value, "formula": formula or {}} def execute(self): try: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py index e67197c270..31c8a5c5ec 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py @@ -20,11 +20,26 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None): + """Removes a cost item + + All associated relationships with the cost item are also removed, + however the related resources, products, and tasks themselves are + retained. + + :param cost_item: The IfcCostItem entity you want to remove + :type cost_item: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + ifcopenshell.api.run("cost.remove_cost_item", model, cost_item=item) + """ self.file = file - self.settings = {"cost_item": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item} def execute(self): # TODO: do a deep purge diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item_quantity.py index 181c8ecb5b..9611a234db 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item_quantity.py @@ -18,11 +18,32 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None, physical_quantity=None): + """Removes a quantity assigned to a cost item + + If the quantity is part of a product (e.g. wall), then the quantity will + still exist and merely the relationship to the cost item will be + removed. + + :param cost_item: The IfcCostItem that the quantity is assigned to + :type cost_item: ifcopenshell.entity_instance.entity_instance + :param physical_quantity: The IfcPhysicalQuantity to remove + :type physical_quantity: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + quantity = ifcopenshell.api.run("cost.add_cost_item_quantity", model, + cost_item=item, ifc_class="IfcQuantityVolume") + # Let's change our mind and delete it + ifcopenshell.api.run("cost.remove_cost_item", model, + cost_item=item, physical_quantity=quantity) + """ self.file = file - self.settings = {"cost_item": None, "physical_quantity": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item, "physical_quantity": physical_quantity} def execute(self): if len(self.file.get_inverse(self.settings["physical_quantity"])) == 1: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py index a20314f32d..69e460d52d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py @@ -18,11 +18,25 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_schedule=None): + """Removes a cost schedule + + All associated relationships with the cost schedule are also removed, + including all cost items. + + :param cost_schedule: The IfcCostSchedule entity you want to remove + :type cost_schedule: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + ifcopenshell.api.run("cost.remove_cost_schedule", model, cost_schedule=schedule) + """ self.file = file - self.settings = {"cost_schedule": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_schedule": cost_schedule} def execute(self): # TODO: do a deep purge diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_value.py index 4f807b8725..7f1421462d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_value.py @@ -18,11 +18,34 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, parent=None, cost_value=None): + """Removes a cost value + + The cost value may be assigned either to a cost item, a construction + resource, or another cost value (i.e. it is a subcomponent of a cost) + + :param parent: The IfcCostItem, IfcConstructionResource, or IfcCostValue + that the IfcCostValue is assigned to. + :type parent: ifcopenshell.entity_instance.entity_instance + :param cost_value: The IfcCostValue that you want to remove + :type parent: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # This cost item will have a unit cost of 5 and a volume of 3 + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 5.0}) + + ifcopenshell.api.run("cost.remove_cost_value", model, parent=item, cost_value=value) + """ self.file = file - self.settings = {"parent": None, "cost_value": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"parent": parent, "cost_value": cost_value} def execute(self): if len(self.file.get_inverse(self.settings["cost_value"])) == 1: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/unassign_cost_item_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/cost/unassign_cost_item_quantity.py index 7cf7efd06d..004b003346 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/unassign_cost_item_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/unassign_cost_item_quantity.py @@ -20,11 +20,52 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, cost_item=None, products=None): + """Removes quantities of a cost item that are calculated on products + + A cost item may have quantities that are parametrically calculated on + physical products. This lets you remove those quantities. This means + that any future changes in the physical product's dimensions will not + have any impact on the cost item. + + :param cost_item: The IfcCostItem to remove quantities from + :type cost_item: ifcopenshell.entity_instance.entity_instance + :param products: A list of IfcProducts that may have parametrically + connected quantities to the cost item + :type products: list[ifcopenshell.entity_instance.entity_instance] + :return: None + :rtype: None + + Example:: + + schedule = ifcopenshell.api.run("cost.add_cost_schedule", model) + item = ifcopenshell.api.run("cost.add_cost_item", model, cost_schedule=schedule) + + # Let's imagine a unit cost of 5.0 per unit volume + value = ifcopenshell.api.run("cost.add_cost_value", model, parent=item) + ifcopenshell.api.run("cost.edit_cost_value", model, cost_value=value, + attributes={"AppliedValue": 5.0}) + + slab = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSlab") + # Usually the quantity would be automatically calculated via a + # graphical authoring application but let's assign a manual quantity + # for now. + qto = ifcopenshell.api.run("pset.add_qto", model, product=slab, name="Qto_SlabBaseQuantities") + ifcopenshell.api.run("pset.edit_qto", model, qto=qto, properties={"NetVolume": 42.0}) + + # Now let's parametrically link the slab's quantity to the cost + # item. If the slab is edited in the future and 42.0 changes, then + # the updated value will also automatically be applied to the cost + # item. + ifcopenshell.api.run("cost.assign_cost_item_quantity", model, + cost_item=item, products=[slab], prop_name="NetVolume") + + # Let's change our mind and remove the parametric connection + ifcopenshell.api.run("cost.unassign_cost_item_quantity", model, + cost_item=item, products=[slab]) + """ self.file = file - self.settings = {"cost_item": None, "products": []} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"cost_item": cost_item, "products": products or []} def execute(self): self.quantities = set(self.settings["cost_item"].CostQuantities or [])