Search code examples
parametersanylogicagent

Create agents with a parameter and a sourceblock


I created my own Flowchart block with a few parameters. Two of them are of the type 'Agent' and in Main I selected the corresponding agents. What my block does is, it creates new agents depending on the agents, that enter the block (kinda like the batch-block).

So far, I was able to verify the incoming agent to make sure, that the right agent-type was selected in Main. Now I want to create the other agent with a source block and the inject function. But here comes my problem. I want to create agents dynamically depending on the selected parameter (type Agent). Obviously, putting just the name of the parameter in the new agent field didn't work (it does work, but only for the first agent - after that I get an error, since the same agent gets created). I know that normally I have to use something like 'new Agent()' to create new agents, but I can't find a link between the parameter-value and the agent-type.

My Issue here is, that I try to make my block as customizable as possible, meaning that I want to use this block in future projects again without changing the code at all (or at least too much). Every project will have different agents, variables, names, parameters, etc.

Edit: Added Screenshot

Simplified version of my block


Solution

  • There are two ways to achieve this: via Java Reflection and using java.util.function.Supplier. Please note that the drawback of both methods is that since the type of the resulting agent is not known in advance the code refers to the new entity as just Agent however it actually creates the agent of correct type, which can be checked using 'instanceof' or cast.

    Both versions are provided below. Example .alp can be found here for the next 2 hrs. In this example there are 2 agents Main and ProgrammaticAgent.

    View of Main agent

    View of ProgrammaticAgent

    Now on to the methods of creation.

    1. Via Java Reflection

    This is the least preferable method of the two. In the example Main agent, the code is in the action property of the 'create directly' button. The code is as follows, please read the comments for more detailed description.

    // This is the name of the class that needs to be created
    //  as a string. It can be passed as a parameter. 
    // NOTE: you need the whole name including package name 
    //  (in this case 'testprogcreation.' but you'll have your own) 
    String classNameValue = "testprogcreation.ProgrammaticAgent";
    
    try {
        // get a handle on the Class of that agent
        Class agentClass = Class.forName(classNameValue);
        
        // find the Constructor
        Constructor c = agentClass.getDeclaredConstructor(
            com.anylogic.engine.Engine.class,
            com.anylogic.engine.Agent.class,
            com.anylogic.engine.AgentList.class);
            
        // Create the agent. Now, because we don't know the type
        // at compile time it has to be declared as 'Agent' here
        // but in actuality it is of type specified in 'classNameValue' above
        Agent agent = 
            (Agent)c.newInstance(getEngine(), this, getDefaultPopulation());
        
        // add to default population
        ((AgentLinkedHashSet<Agent>)getDefaultPopulation())._add(agent);
            
        // set up parameters by name
        agent.setParameter("parameterOne", 5.0, false);
        agent.setParameter("parameterTwo", "some value", false);
        agent.markParametersAreSet(); // <- mark that parameters are set
    
        // tell AnyLogic that agent is created and started  
        agent.create();
        agent.start();
        
        // now you can do whatever with the agent, in this case send it
        // via 'enter' into some process
        enter.take(agent);
    } catch (Exception e) {
        e.printStackTrace();
        error("Could not instantiate %s, see Console for full error", classNameValue);
    }
    
    1. Via function Supplier

    This is a much neater method. Here the block that will be creating new agents has a dynamic parameter called agentSupplier (see image) of type java.util.function.Supplier and calls agentSupplier.get() when new instance of an agent is needed.

    This Supplier is then provided with a reference to 'add_' method which is automatically generate by AnyLogic when an agent population object is created. In this case the population is called 'programmaticAgents' and therefore the method is called 'add_programmaticAgents(...'.

    agentCreator parameter

    Note that in the above image the code in the Default Value field would actually be changed in the enclosing agent to reflect the correct automatically create method.