Method to Connect Functional and Physical Architectures

Hello,
I have a question about how to best connect the elements of a functional and physical architecture.

The information that I’m missing from the following example is which product performs which product function within the system function.

Some questions:

  1. Does this method generally make sense?
  2. If yes, how can I model the following: In SystemFunction, ProductFunctionA is performed by ProductA?

Thanks!

package ProductFunctionExample {

    package SystemFunctions{

        action def SystemFunction {
            action productFunctionA : ProductFunctions::ProductFunctionA;
            action productFunctionB : ProductFunctions::ProductFunctionB;

            flow from productFunctionA.myFunctionalItem to productFunctionB.myFunctionalItem;
        }

    }

    package ProductFunctions {
        action def ProductFunctionA {
                out item myFunctionalItem : FunctionalItems::MyFunctionalItem;
            }
        action def ProductFunctionB {
                in item myFunctionalItem : FunctionalItems::MyFunctionalItem;
            }
    }


    package Systems {
        part def System {
            part productA : Products::ProductA;
            part productB : Products::ProductB;

            action systemFunction : SystemFunctions::SystemFunction;
        }
    }

    package Products {

        part def ProductA {
            action productFunctionA : ProductFunctions::ProductFunctionA;
        }

        part def ProductB {
            action productFunctionB : ProductFunctions::ProductFunctionB;
        }

    }

    package FunctionalItems {
        item def MyFunctionalItem;
    }

}

In Systems::System:

allocate systemFunction.productFunctionA to productA;

Hi Tom,

The approach does make sense to separate functional and physical architectures. Your snippet was missing definitions for ProductA/B so I assume they could:

  • A) Do not own any action usages (could use allocation method Brian proposed) but then you are not modelling behavior of individual product in isolation, which I think is not your intention (i.e. it is a missed opportunity that makes model harder to maintain because it is not obvious at a glance the complete list of functions product does).
  • B) Have placeholder action usages without types just for linking with those product functions under “systemFunctions”. Names can differ here and actions under products reference subset actual systemFunction.. These action usages can be inlined directly within System part def products or redefine existing action usages inherited from ProductX part defs.
  • C) Have actions usages typed with the same ProductFunctions::ProductFunction definitions, and ref part to the System or ref action SystemFunctions. Then all this mapping (either referencing or binding) could be done withing part def Product B (C step1) and only when using this ProductX definition in System part def, you need to redefine the reference part/action usage (C step 2). Nice thing here is that all linking is happening in the Product defintions, and the main System part def is has details hidden away.
  • D) Have same identical action under the System::systemFunction and System::. Since they both are the same, we could show that by binding them together (remember binding is bidirectional, so it could be done anywhere in System part def, but I recommend either D1 or D2 option).
package ProductFunctionExample {
    package SystemFunctions {
        action def SystemFunction {
            action productFunctionA : ProductFunctions::ProductFunctionA;
            action productFunctionB : ProductFunctions::ProductFunctionB;

            flow from productFunctionA.myFunctionalItem to productFunctionB.myFunctionalItem;
        }
    } // package SystemFunctions

    package ProductFunctions {
        action def ProductFunctionA {
            out item myFunctionalItem : FunctionalItems::MyFunctionalItem;
        }
        action def ProductFunctionB {
            in item myFunctionalItem : FunctionalItems::MyFunctionalItem;
        }
    } // package ProductFunctions

    package FunctionalItems {
        item def MyFunctionalItem;
    } // package FunctionalItems

    package Products {
        part def ProductA {
            // Option B: different product action usage with its own def
            action a2 : A2;

            // Option C: same action usages under systemFunction and productA
            action productFunctionA : ProductFunctions::ProductFunctionA;
        }

        action def A2 {
            // TBD all action internal action flows
        }

        part def ProductB {
            // Option C (step 1): products have reference to system functions
            ref action sf : SystemFunctions::SystemFunction;
            action b2 references sf.productFunctionB;
            action b3 = sf.productFunctionA;

            // Option D: same action usages under systemFunction and productB
            action productFunctionB : ProductFunctions::ProductFunctionB;
        }
    } // package Products

    package Systems {
        part def System {
            part productA : Products::ProductA {
                // Option B1: product owned action useage references the system function
                action a1 references systemFunction.productFunctionA;
                // Option B2: redefine existing action with reference
                action :>> a2 references systemFunction.productFunctionB;

                // Option D1: exactly the same action under systemFunction action usage and here
                action :>> productFunctionA = systemFunction.productFunctionA;
            }
            part productB : Products::ProductB {
                // Option C (step2): bind the System systemFunction to reference sf
                ref action :>> sf default systemFunction; // could be non-default binding also
            }

            action systemFunction : SystemFunctions::SystemFunction {
                // Option A1:
                allocate productFunctionB to productB;

                // Option D2: Binding could also be done here
                action :>> productFunctionB = productB.productFunctionB;
                // or via binding keyword
                bind productFunctionB = productB.productFunctionB;
            }

            // Option A2:
            allocate systemFunction.productFunctionB to productB;

            // Option D3: Binding could also be done here
            bind systemFunction.productFunctionB = productB.productFunctionB;
        }
    } // package Systems
} // package ProductFunctionExample


All options have their pros and cons and depends how your team work together. Probably binding would be the most appropriate as I understand each function (action) under systemFunction action def is performed (and actually owned) by one or another product.

Probably there are more ways how to do it but I think one of these options should be sufficient. Let me know if you have further questions!

Kind regards,
Kestutis

Thank you Brian and Kestutis!

From all the options you shared, which one would be best to generate a swimlane diagram per system function using Syside? I’m thinking of something similar to the diagram below:

  • The diagram boundary represents the system function boundary (potentially with in/out items)
  • Each swimlane represents a product participating in the system function
  • Each product’s functions are nested within its swimlane
  • Functions are connected with each other via item flows
  • Product function interfaces realizing system function interfaces are connected via bindings

Thanks!
Tom

My suggestion would also be allocations between model elements of architecture models on different abstraction levels, e.g. the Functional or Logical Architecture and the Technical or Physical Architecture, be it parts or actions or connections. But what we suggest is to use typed allocation defs to keep different sorts of allocation. E.g. in a recent publication on Embedded World Congress (see paper and slide deck here: (PDF) Informed Systems Engineering Decision-making Through SysML v2 Modelling) we had the abstraction levels FunctionBlockArchitecture, SolutionConceptArchitecture and TechnicalArchitecture, the latter then split into SoftwareArchitecture and HardwareArchitecture. Between FunctionBlockArchitecture and SolutionConceptArchitecture we use allocation usages of the def “realizedAs”. Between SolutionConceptArchitecture and elements of the HardwareArchitecture or SoftwareArchitecture we use allocation usages of the def “implementedBy”. Between application software parts and the OS / middleware we use “scheduledBy” and between software and software-executing hardware parts (like CPU cores) we use “runsOn”. This allows fine-grained filtering for views and external tools that govern the build process.

Best regards

Bernhard