creating custom function objects from an external plugin

Development of custom GMAT plugins

creating custom function objects from an external plugin

Postby marchand » Tue May 22, 2012 2:10 pm

In the process of developing an external plugin, we found the MatlabInterface source was most representative of what we were trying to do. So, we modelled our external plugin loosely after the MatlabInterface plugin and used that source as a model to develop a barebones type wrapper that would interface with an external non-matlab type engine. We had partial success with this approach, but in the process quickly realized that a MatlabFunction is deeply embedded within the GMAT tree, not just a plugin, even though the MatlabInterface source appears under the GMAT trunk’s plugins folder.

The execution of the test code stopped at line 910 of src/base/command/CallFunction.cpp in the GMAT trunk, the Initialize method. Within it, there’s a check on line 938 that checks to see if the Function is a GmatFunction or a MatlabFunction and, if it isn’t, an error is returned. After that, we started grepping for MatlabFunction objects within the trunk and noticed they appear in many places outside the plugins folder and within the GMAT trunk.

So, here's the question. Is there a way to create a custom function object from a plugin that can be called from a GMAT script, much in the same way the MatlabFunction works?


  • If yes, do you have any insight or suggestions into how to implement that? We were unable to deduce that from any of the available documentation.
  • If no, is there another object type that we can extend that gives us the ability to call it from the script interface that takes some input and provides some output in a single call?

Thanks!
marchand
 
Posts: 86
Joined: Tue Feb 21, 2012 2:42 pm

Re: creating custom function objects from an external plugin

Postby DJCinSB » Wed May 23, 2012 1:00 am

What you are running into here is a defect in the current implementation of functions inside of GMAT. Basically, there is an abstraction layer missing between the Function and MatlabFunction classes -- call it ExternalFunction -- that would make this task simpler. That class would define the methods that all external functions would use, and would provide those interfaces to the CallFunction command (and other function interface classes), which would work exclusively with a reference to that abstract class. Unfortunately, I don't see how that could be added to the GMAT code base between now and the operational release scheduled for the end of the year, so we need to see what alternatives are available, unless one of the other GMAT developers has an alternative that I haven't thought about yet. (Note that I haven't looked extensively into how to do this yet -- there may be a simpler approach out there!)

One approach for this would be to write a new command that provides the functionality that you need. For instance, suppose that what you need to be able to do is something like this:
Code: Select all
Create MarchandFunction funct;
...
BeginMissionSequence
...
[output1 output2] = funct(input1 input2 input3)
...

This could be reworked to look like this (this is quite crude here, and should be refined to match what you need):
Code: Select all
Create MarchandFunction funct;
...
BeginMissionSequence
...
Generate (output1 output2) from funct(input1 input2 input3)
...

where you'd write the Generate command to make the external call. That way you would just avoid the issues with the type-specific code in the CallFunction command and other parts of GMAT. (You might even be able to derive a new command from the CallFunction command -- something like ExtendedCallFunction -- to call your function code. I suspect that the missing abstraction layer would make this problematic, though.)

Do you have a sample of how you'd like to script the added feature that I can take a look at? I might be able to come up with a more elegant approach if I can see what you really need to do here. (Feel free to send it privately if necessary, of course. My e-mail is djc@thinksysinc.com.)

- Darrel
DJCinSB
 
Posts: 274
Joined: Mon Jun 09, 2008 3:57 pm

Re: creating custom function objects from an external plugin

Postby jason » Mon Jun 04, 2012 2:51 pm

Darrel,

I believe the above example would work. I created a command that extends GmatCommand and also created a factory and the command is being constructed properly but I am still unclear on how the command string is parsed and executed. Do we have to handle parsing the string? I noticed that I am getting an exception thrown from the Interpreter class around line 2136 and upon further inspection, I'm not sure I know how the command string gets parsed and passed to my command for execution. Is there an example of a plugin that does this? If not, any guidance would be appreciated.

Jason
jason
 
Posts: 1
Joined: Mon Jun 04, 2012 2:40 pm

Re: creating custom function objects from an external plugin

Postby DJCinSB » Mon Jun 04, 2012 3:44 pm

That is one downside to writing your own command -- you do need to write the parser as well. Several of the commands in GMAT do show how to do this. The command parsing is done in the InterpretAction method. A basic example of this is the Maneuver command (in src/base/command/Maneuver.cpp, pasted here with the debug removed):
Code: Select all
bool Maneuver::InterpretAction()
{
   StringArray chunks = InterpretPreface();

   // Find and set the burn object name ...
   StringArray currentChunks = parser.Decompose(chunks[1], "()", false);

   if (currentChunks.size() < 2)
      throw CommandException("Missing Maneuver parameter. Expecting "
                             "\"ImpulsiveBurnName(SpacecraftName)\"\n");

   SetStringParameter(burnNameID, currentChunks[0]);

   // ... and the spacecraft that is maneuvered
   currentChunks = parser.SeparateBrackets(currentChunks[1], "()", ",");
   if (currentChunks.size() > 1)
      throw CommandException("Unexpected text after spacecraft name in Maneuver command\n");

   SetStringParameter(satNameID, currentChunks[0]);

   return true;
}

The approach here is very much one of "divide and conquer." The Maneuver command looks like this:
Code: Select all
Maneuver impulseObject(spacecraftObject)

so the InterpretPreface call breaks this line into 2 pieces: "Maneuver" and "impulseObject(spacecraftObject)". I ignore the first here -- the only way to get into this part of the code is if chunks[0] == "Maneuver" -- and work on the second, breaking it apart at the parentheses using the Decompose call on the TextParser (see src/base/util/TextParser.?pp) that the command inherits from the GmatCommand base class. Those pieces are then passed as strings into the buffers that need them when the command is configured for a run.

The Propagate command is an example of quite complex parsing; there are a lot of permutations for that particular command, so its InterpretAction method needs to handle those complexities. I wouldn't recommend reading that one first, though -- the Propagate code could use some serious refactoring as a whole! -- but it might give some pointers about handling more involved pieces.

I have a couple of commands in some plugin code that include this type of parsing as well on a different project. If things still seem muddy after you look at those examples, let me know and I'll see if I can share them with you.
DJCinSB
 
Posts: 274
Joined: Mon Jun 09, 2008 3:57 pm

Re: creating custom function objects from an external plugin

Postby davidf » Tue Jul 10, 2012 3:19 pm

Darrel-

Jason got a simple example working using your suggestions. We're moving to increasing complexity, so we're re-examining some of the "black box" steps that we took from your example. Specfically the SetStringParameter line. I *think* that this is just storing the string value that's been parsed in some member variable structure defined deep in the GMAT class tree. Is that correct? Assuming that it is correct, are their GMAT-specific reasons that we need to store the data that way vs., e.g., defining our own member variable in our Plugin class and storing the data there?

Thanks.

David
davidf
 
Posts: 6
Joined: Tue Jul 10, 2012 2:58 pm

Re: creating custom function objects from an external plugin

Postby DJCinSB » Tue Jul 10, 2012 3:40 pm

Actually, the SetStringParameter is a bit of overkill in that example. The call just passes the string into the Maneiver command's internal std::string burnName variable. I have a tendency to do this type opf thing by calling the SetxxxParameter method so that if there is code checking that the new value is good or bad, it has a chance to be exercised. FOr this case, though, the SetStringParameter code looks like this (see lines 485 and following in Maneuver.cpp):
Code: Select all
bool Maneuver::SetStringParameter(const Integer id, const std::string &value)
{
   if (id == burnNameID) {
      burnName = value;
      return true;
   }

   if (id == satNameID) {
      satName = value;
      return true;
   }

   return GmatCommand::SetStringParameter(id, value);
}

so all that happens is the name is set on the internal variable. Doing that directly has the same effect (and, of course, is more efficient), so that is most likely the way you'll want to do it.

- Darrel
DJCinSB
 
Posts: 274
Joined: Mon Jun 09, 2008 3:57 pm


Return to Plugin Development

Who is online

Users browsing this forum: No registered users and 1 guest

cron