How to Block a Product or Control Need/Feed Matching

Hello everyone,

Description:
A device flows into the system starting from the input node, passes through one or more test sites, and finally exits at the output node according to the following rules:

  1. The device must be tested again if it fails a test before reaching the finish line.
  2. It cannot use the same test site that it has already visited.

The material flow of the system is shown below:

Question:
Let me clarify my questions before describing what I’ve tried:

  1. How can I block a product that has a specific property value?
  2. How can I manage the matched Need and Feed connections using the Python API?
  3. Additionally, is it possible to create a custom vcProductFilter object that allows us to accept or reject a product instance based on our own logic?

Something I’ve tried…

According to the VC Help documentation about vcProductMatcher, it says:

A match can be made if the process group ID of the Need and Feed matches, the product type is accepted by the Need (defined in vcProductFilter), and a valid transport solution exists between the transport nodes.

Based on this, I tried creating a property called Use_Site on the Device to record which test sites it has already used.
Then, I set a Product Filter in the process statement of each site.

However, I’m not sure how to write the correct expression, or even which type of filter I should be using.
It seems that the filter expression doesn’t allow syntax like "str" not in "str".

I encountered an error in the expression used in the statement’s filter. The message looks like this:

Error in . Expression '"Test Site #22" not in Product.Component.Use_Site' refers to the variable itself.

I also tried handling the Need / Feed match through the Python API.
I called match.tryCancelMatch(), but it returned None, and the match state remained in Create.

Hmm… it seems that the match can’t be canceled as I expected.

def register_match(new_):
  """
  Register a match event for need/feed and handle the match logic.
  """
  def need_feed_match(match):  # type: (vcProductNeedFeedMatch) -> Any
    transport_ = next(x for x in transport_items if x.need_item == new_ or x.feed_item == new_) # type: TransportItem
    if not transport_:
      error('No TransportItem found!')
      return
    #mo
    print("==========================================")
    if match.State == VC_MATCH_STATE_CREATED:
      match_state = "Created"
    elif match.State == VC_MATCH_STATE_CANCELLED:
      match_state = "Cancelled"
    elif match.State == VC_MATCH_STATE_FINALIZED:
      match_state = "Finalized"
    elif match.State == VC_MATCH_STATE_DISPOSED:
      match_state = "Disposed"
    print("This Match Object Type: {}".format(match_state))
    print("Matched Need's "
          "Target Node: {}".format(match.MatchedNeed.TargetNode.Component.Name))
    print("Matched Feed's "
          "Source Node: {}".format(match.MatchedFeed.SourceNode.Component.Name))
    print("Matched Product Instance:\n\t"
          "Product's Mark: {}\n\t"
          "Product's Used Site: {}".format(match.MatchedFeed.Product.Component.Mark,
                                         match.MatchedFeed.Product.Component.Use_Site))
    if comp.Name in match.MatchedFeed.Product.Component.Use_Site and transport_.type == 'need':
      print("This matched need feed should be canceled!")
      print(match.tryCancelMatch())
      print("This Match Object Type: {}".format(match_state))
      print("==========================================")
      return
    else:
      print("==========================================")
      
    transport_.need_item = match.MatchedNeed
    transport_.feed_item = match.MatchedFeed
    transport_.match_item = match
    transport_.match_time = sim.SimTime
    transport_.product = match.MatchedFeed.Product
    create_transport_target(transport_, match.MatchedFeed.Product, transport_.type)
    if transport_.type == 'feed':
      solution = transport_system.findSolution(
        transport_.feed_item.SourceNode,
        transport_.need_item.TargetNode,
        transport_.product.ProductType.FlowGroup
      )
      transport_.product.TransportSolution = solution
      transport_node.beginTransportOut(transport_.product)
    match.finalizeMatch()
  return need_feed_match
VC OUTPUT PANEL:
==========================================
This Match Object Type: Created
Matched Need's Target Node: SLT Trolley Test Unit #22
Matched Feed's Source Node: PlatformBase
Matched Product Instance:
	Product's Mark: R0
	Product's Used Site: SLT Trolley Test Unit #22,
This matched need feed should be canceled!
None
This Match Object Type: Created
==========================================

The expression language / syntax is defined in the help. Operations on strings and lists are limited.

See the different sub-pages under the Expressions topic, not just this Functions page.

AFAIK as of VC 4.10 the product match cancellation is not working quite as expected / useful from design perspective, the native statements won’t try to find another match if your logic cancels one.

This general requirement of visiting each test site max once sounds like it could be solvable using the process visit limits feature, at least if you make each site a separate process but have them as alternatives in a flow step.

I didn’t notice there were such limitations before, but now I see.
Maybe I’ll try setting multiple properties on the dynamic component to record the used sites separately. This might allow me to use something like Product.Component.<prop> == <site name> ? True : False to accept or reject specific products, and then combine those filters with the && operator.

Thanks, TSy, for sharing your knowledge.
I’m a bit concerned about using “separate processes but having them as alternatives in a process group,” because there aren’t just 3 sites like in the example I drew — there are actually 18, each device has five lives before it dies (fails in the test), haha. But I’ll give it a try :sweat_smile: or maybe I’ll need another way to set up my model.