Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

possible analogfunction bug #69

Open
wants to merge 1 commit into
base: analogfunction
Choose a base branch
from
Open

Conversation

felix-salfelder
Copy link
Member

need to access analogfunction calls on right hand sides of assignments and
contributions. this patch pushes these calls into rhs/function.

indeed, that seems to be working in

<admst:for-each select="rhs/function">
<admst:message format="rhs function %(.)\n"/>
</admst:for-each>

but i get "admst transform unexpected" in

<admst:for-each select="rhs/function">
<admst:apply-templates select="." match="something"/>
</admst:for-each>

need to access analogfunction calls on right hand sides of assignments and
contributions. this patch pushes these calls into rhs/function.

indeed, that seems to be working in

<admst:for-each select="rhs/function">
  <admst:message format="rhs function %(.)\n"/>
</admst:for-each>

but i get "admst transform unexpected" in

<admst:for-each select="rhs/function">
  <admst:apply-templates select="." match="something"/>
</admst:for-each>
@tvrusso
Copy link

tvrusso commented Nov 26, 2019

Since I sparked interest in addressing this issue, I should comment at this point that it would be a very bad thing to add analog function calls to the "function" list of an expression as this pull request would do.

This is because almost every code generating back-end in the wild is derived from Laurent Lemaitre's original design, and they all use the "function" list to generate function precomputation for assignments --- that is, if an assignment has a function call on the RHS, all the function calls are done in precomputation steps, and their derivatives also generated in a precomputation step. The variables used for precomputation are then used instead of the function call when the assignment itself is generated.

In these back-ends, it is ASSUMED that analog functions are not in that list, and those are handled in a completely different manner. If ADMS started putting analog function calls into "function" all of these back-ends would break. Any back-end without Lemaitre pedigree that needs this sort of thing should do so by having their own adms.implicit.xml and using it instead of ADMS's default version (by using "-x -e /path/to/my/adms.implicit.xml").

That said, for Xyce/ADMS's purposes I found that the method that Lemaitre's analog function code uses to generate analog function derivatives is extremely inefficient for models that make extensive use of analog functions, especially analog functions that call other analog functions. For our needs, we will want to do analog function precomputation in manner similar to that used for builtin functions. I was successful at getting these calls into the "function" list without the failures you observed. I did this by putting the push of the call in a different place. Just in case anyone reading this is developing their own ADMS back-end without relying on Laurent Lemaitre's original analog function implementation, I'm providing the explanation. As noted, it should NOT be done in ADMS's implicit templates, because it would be harmful to existing back-ends.

Farther down in adms.implicit.xml than where you have done this, there is the following code:

    <!-- Table 4-14 - Standard Functions -->
    <!-- Table 4-15 - Trigonometric and Hyperbolic Functions-->
    <admst:when
      test="[name='analysis' or name='\$analysis' or name='\$simparam' or name='simparam' or                                                               
      name='\$shrinka' or name='\$shrinkl' or name='\$limexp' or name='limexp' or name='\$limit' or                                                        
      name='ln' or                                                          
      name='log' or                                                         
      name='exp' or                                                         
      name='sqrt' or                                                        
      name='min' or                                                         
      name='max' or                                                         
      name='abs' or                                                         
      name='pow' or                                                         
      name='floor' or                                                       
      name='ceil' or                                                        
      name='sin' or                                                         
      name='cos' or                                                         
      name='tan' or                                                         
      name='asin' or                                                        
      name='acos' or                                                        
      name='atan' or                                                        
      name='atan2' or                                                       
      name='hypot' or                                                       
      name='sinh' or                                                        
      name='cosh' or                                                        
      name='tanh' or                                                        
      name='asinh' or                                                       
      name='acosh' or                                                       
      name='atanh'                                                          
      ]">
      <admst:push into="$globalexpression/function" select="."/>
      <admst:value-to select="class" string="builtin"/>
    </admst:when>
    <admst:when test="[name='transition']">
      <admst:push into="$globalexpression/function" select="."/>
    </admst:when>
    <admst:otherwise>
      <admst:assert test="[exists(definition)]" format="%(lexval/(f|':'|l|':'|c)): analog function '%(name)' is undefined\n"/>
    </admst:otherwise>
  </admst:choose>
</admst:when>

This is where the builtin functions are already being pushed into the function list. The final "otherwise" only gets executed for analog function calls, and in its existing version just tests that the function being called is defined. This can easily be modified:

    <!-- Table 4-14 - Standard Functions -->
    <!-- Table 4-15 - Trigonometric and Hyperbolic Functions-->
    <admst:when
      test="[name='analysis' or name='\$analysis' or name='\$simparam' or name='simparam' or                                                               
      name='\$shrinka' or name='\$shrinkl' or name='\$limexp' or name='limexp' or name='\$limit' or                                                        
      name='ln' or                                                          
      name='log' or                                                         
      name='exp' or                                                         
      name='sqrt' or                                                        
      name='min' or                                                         
      name='max' or                                                         
      name='abs' or                                                         
      name='pow' or                                                         
      name='floor' or                                                       
      name='ceil' or                                                        
      name='sin' or                                                         
      name='cos' or                                                         
      name='tan' or                                                         
      name='asin' or                                                        
      name='acos' or                                                        
      name='atan' or                                                        
      name='atan2' or                                                       
      name='hypot' or                                                       
      name='sinh' or                                                        
      name='cosh' or                                                        
      name='tanh' or                                                        
      name='asinh' or                                                       
      name='acosh' or                                                       
      name='atanh'                                                          
      ]">
      <admst:push into="$globalexpression/function" select="."/>
      <admst:value-to select="class" string="builtin"/>
    </admst:when>
    <admst:when test="[name='transition']">
      <admst:push into="$globalexpression/function" select="."/>
    </admst:when>
    <admst:otherwise>
      <admst:assert test="[exists(definition)]" format="%(lexval/(f|':'|l|':'|c)): analog function '%(name)' is undefined\n"/>
      <admst:push into="$globalexpression/function" select="."/>
    </admst:otherwise>
  </admst:choose>
</admst:when>

That is, just push the function into "function" right after the assert.

As soon as one does this, one will cause all the precomputation code of existing back ends to be broken, because they are counting on no analog function calls being in the list. So this technique should be reserved for ADMS users who have rewritten their code generators and are overriding ADMS's implicit rules with their own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants