Fortran-FOSS-Programmers / ford

Automatically generates FORtran Documentation from comments within the code.
https://forddocs.readthedocs.io
GNU General Public License v3.0
405 stars 131 forks source link

Missing "read more" button on derived types pages #565

Closed tuncaen closed 11 months ago

tuncaen commented 11 months ago

Hi,

I sometimes write long explanations for procedures. They used to be displayed as a few lines with a "read more" button. However, my last run yields all the procedure explanations of the derived types appear in bulk on the main page. This issue arises on the derived type pages. I attached some screenshots, the former from the modules pages the latter from the derived type pages.

module_page dt_page

This makes the main page of the derived types a bit messy. Is there any way to add the read more button into derived types pages as in the modules pages?

ZedThree commented 11 months ago

Sorry it's taken me awhile to get to this, I don't have very much time for Ford at the moment!

Hmm, that's a bit odd, I'm pretty sure it should be only displaying the summary. I think the relevant bit is here: https://github.com/Fortran-FOSS-Programmers/ford/blob/abec2a571e16e867fbbfec347c6d5db5ba6d9348/ford/templates/macros.html#L258

It looks like the routine BasisFuns has its own page, so presumably it is visible, so possibly full_docstring is being set incorrectly somewhere.

Is this project public? If not, would you be able to supply a stripped down minimal example?

tuncaen commented 10 months ago

Hi, @ZedThree, sorry for the late answer, here is the minimal example,

src/BasisFunctions.f90

module BasisFunctions

    !< The module defining spline basis objects and their arguments
    integer, parameter :: wp  = selected_real_kind(15,307)  !< 15 digits, range \([10^{-307} , 10^{+307}  - 1]\); 64 bits.

    implicit none

    private

    public :: basis

    !# **Spline [[basis(type)]] class**  
    !  Procedures (methods) of this class assume that the spline basis defined by an **open knot vector**
    !   Object constructor function of this derived type is [[basis(interface)]]       
    type :: basis
        !<  
        integer                 ::  p       !< Polynomial degree \(p\)
        integer                 ::  nk      !< Number of the knots
        integer                 ::  m       !< The highest index of the knots ` ( nk-1 ) `
        integer                 ::  nb      !< Number of basis functions
        integer                 ::  n       !< The highest index of the basis functions ` ( nb-1 ) `
        real(wp),   allocatable ::  kv(:)   !< [Open knot vector](../page/01.fooiga/eqns.html#openvec)  
                                            !< ` kv(0:m) ` \( = \left\{u_{0},..., u_{m}\right\} \)

    contains
        procedure, public   :: FindSpan                 !< **Knot span index search                                                                     **
        procedure, public   :: BasisFuns                !< **Computation of the non-vanishing basis functions                                           **                                                     **

        !# Overloading `=`.
        generic             :: assignment(=)        =>  assign_basis
        procedure, public   :: assign_basis  !< **Overloading `=`.   **
    end type basis

    !***************************************************************************************************************************
    ! **OBJECT CONSTRUCTOR**  
    ! - Basis       (Int)  
    ! =>
        !> **Spline basis constructor**  
        interface basis
            procedure basisConstructor
        end interface

    !***************************************************************************************************************************

    contains

    !***************************************************************************************************************************
    ! **METHODS OF `BASIS` TYPE**  
    ! - FindSpan            (Fn)   
    ! - BasisFuns           (Sub)  
    ! =>

        !# 
        pure elemental function FindSpan(me,u) result (span)
            class(basis), intent(in)    :: me
            real(wp), intent(in)        :: u        !< Given \( u \) value
            integer                     :: span     !< Index of the corresponding knot span
            !locals
            integer :: low, high    !< indices for binary search

            associate( p => me%p, Ui => me%kv, n => me%n ) !get rid of % signs
            !/* Special cases */
            if (u >= Ui(n+1)) then
                span = me%n
                return
            end if
            if (u <= Ui(p)) then
            span = p
            return
            end if
            !/* Do binary search */
            low = p; high = n+1
            span = (low + high) / 2
            do while (u < Ui(span) .or. u >= Ui(span+1))
                if (u < Ui(span)) then
                    high = span
                else
                    low  = span
                end if
                span = (low + high) / 2
            end do
            end associate

        end function FindSpan
        ! .......................................................

        !# {!BasisFuns.md!}
        pure subroutine BasisFuns(me,u,N,span)
            class(basis), intent(in)                :: me
            real(wp),       intent(in)              :: u            !< Given \( u \) value
            integer,        intent(in), optional    :: span         !< Knot span where \( u \) lies on
            real(wp),       intent(out)             :: N(0:me%p)    !< \( =  \{ N_{i-p,p}(u) \ldots N_{i,p}(u)\} \)
            !locals
            integer     :: i    !< Knot span index
            integer     :: j, r
            real(wp)    :: left(me%p), right(me%p), saved, temp!, w

            associate( p => me%p, Ui => me%kv ) !get rid of % signs

            ! set the knot span
            if(present(span))then
                i = span
            else
                i = me%FindSpan(u)
            end if

            N = 0.0_wp; right=0.0_wp; left=0.0_wp

            N(0) = 1.0_wp
            do j = 1, p
            left(j)  = u - Ui(i+1-j)
            right(j) = Ui(i+j) - u
            saved = 0.0_wp
            do r = 0, j-1
                temp = N(r) / (right(r+1) + left(j-r))
                N(r) = saved + right(r+1) * temp
                saved = left(j-r) * temp
            end do
            N(j) = saved
            end do

            end associate

        end subroutine BasisFuns
        ! .......................................................

    !***************************************************************************************************************************

    !***************************************************************************************************************************
    ! **TYPE CONSTRUCTORS**  
    ! - basis_constructor   (Fn)  
    ! =>

        !# 
        pure function basisConstructor(nk,p,k) result(me)
            integer, intent(in)             :: nk       !< Number of the knots
            integer, intent(in)             :: p        !< Polynomial degree \(p\)
            real(wp), intent(in)            :: k(nk)    !< [Open knot vector](../page/01.fooiga/eqns.html#openvec)  
                                                        !< ` kv(0:m) ` \( = \left\{u_{0},..., u_{m}\right\} \)
            type(basis)                     :: me       !< Spline basis object
            !locals
            integer                     :: i

            me%nk = nk
            me%m  = nk - 1
            me%p  = p
            me%nb  = nk - ( p + 1 )     !number of basis functions or control points
            me%n   = me%nb - 1          !highest index of the basis functions or control points
            allocate(me%kv(0:nk-1), source=k)

        end function basisConstructor
        ! .......................................................

    !***************************************************************************************************************************

    !***************************************************************************************************************************
    ! **OPERATOR OVERLOADING**  
    ! - assign_basis  ( `basis=basis` )   (Sub)  
    ! =>

        !# Overloading for assignment `=` operator, 
        pure elemental subroutine assign_basis(lhs, rhs)
            class(basis), intent(inout) :: lhs !< Left hand side.
            type(basis), intent(in) :: rhs !< Right hand side.

            lhs%p       = rhs%p       
            lhs%nk      = rhs%nk      
            lhs%m       = rhs%m       
            lhs%nb      = rhs%nb      
            lhs%n       = rhs%n       
            if(allocated(lhs%kv)) deallocate(lhs%kv)
            allocate(lhs%kv, source = rhs%kv) 

        endsubroutine assign_basis
        ! .......................................................

    !***************************************************************************************************************************

end module BasisFunctions

src_comment/BasisFuns.md

Computes the nonvanishing basis functions based on Algorithm A2.2 in the NURBS Book [^1].  

### Implementaton Details of Algorithm A2.2 {#A2.2}

Let  \( U=\{u_{0}, \ldots ,u_{m}\}\) be a nondecreasing sequence of real numbers, i.e., \(u_{i} \leq u_{i+1}\), \(i=1, \ldots ,m-1\). The \(u_{i}\) are called *knots*, and \(U\) is the *knot vector*. The \(i\)th B-spline basis function of \(p\)-degree (*order* \(p+1\)), denoted by \(N_{i,p}(u)\), is defined as  

<span type="math display" id="2-5">
    \begin{equation}
    \begin{gathered}
        N_{i, 0}(u)=\left\{\begin{array}{ll}{1} &
        {\text { if } u_{i} \leq u<u_{i+1}} \\
        {0} & {\text { otherwise }}\end{array}\right. \\
        N_{i, p}(u)=\dfrac{u-u_{i}}{u_{i+p}-u_{i}} N_{i, p-1}(u)
        +\dfrac{u_{i+p+1}-u}{u_{i+p+1}-u_{i+1}} N_{i+1, p-1}(u).
    \end{gathered}
    \tag{2.5}
    \end{equation} </span>

Note that  

- \(N_{i,0}(u)\) is a step function, equal to zero everywhere except on the half-open interval \({[u_{i}, u_{i+1})}\);  
- for \(p>0\), \(N_{i,p}(u)\) is a linear combination of two (\(p-1\))-degree basis functions  
- computation of a set of basis functions requires specification of a knot vector, \(U\), and the degree, \(p\);  
- [Equation (2.5)](#2-5) can yield the quotient \(0/0\); we define this quotient to be zero  
- the half-open interval, \({[u_{i}, u_{i+1})}\), is called the *\(i\)th knot span*; it can have zero length, since knots need not be distinct  

---

Assuming \(u\) is in the \(i\)th span, \(i=0,\ldots,n\), computation of the nonzero functions results in an inverted triangular scheme  

![Algorithm 2.2](|media|/img/img_A2.2.png#small)

Algorithm computes all of the non-vanishing basis functions in an efficient way, [see example](#ex2-3), and return them in the array [` N(0:p) `]. There is no risk of division by zero as we can encounter in [Cox-de Boor recursion formula](#2-5).  

**Note:** *This algorithm applies to rational basis functions.*

#### ***Ex2.3 Nonvanishing Basis Functions*** {#ex2-3}

There is a great deal of redundant computation inherent in [Cox-de Boor recursion formula](#2-5). For example, writing out the second-degree functions in general terms, we have

<span type="math display" id="2-14">
 \begin{equation}
  {N_{i - 2,2}}(u) = \frac{{u - {u_{i - 2}}}}{{{u_i} - {u_{i - 2}}}}{N_{i - 2,1}}(u) - \frac{{{u_{i + 1}} - u}}{{{u_{i + 1}} - {u_{i - 1}}}}{N_{i - 1,1}}(u)
 \tag{2.14}
 \end{equation} </span>

<span type="math display" id="2-15">
 \begin{equation}
  {N_{i - 1,2}}(u) = \frac{{u - {u_{i - 1}}}}{{{u_{i + 1}} - {u_{i - 1}}}}{N_{i - 1,1}}(u) - \frac{{{u_{i + 2}} - u}}{{{u_{i + 2}} - {u_i}}}{N_{i,1}}(u)
 \tag{2.15}
 \end{equation} </span>

<span type="math display" id="2-16">
 \begin{equation}
  {N_{i,2}}(u) = \frac{{u - {u_i}}}{{{u_{i + 2}} - {u_i}}}{N_{i,1}}(u) - \frac{{{u_{i + 3}} - u}}{{{u_{i + 3}} - {u_{i + 1}}}}{N_{i + 1,1}}(u)
 \tag{2.16}
 \end{equation} </span>

Note that  

- the first term of [Eq. (2.14)](#2-14) and the last term of [Eq. (2.16)](#2-16) are not computed, since \(N_{i-2,1}(u)\) \(= N_{i+1,1}(u)\) \( = 0\);  
- the expression \(\frac{{N_{i - 1,1}}(u)}{{{u_{i + 1}} - {u_{i - 1}}}}\) which appears in the second term of [Eq. (2.14)](#2-14) appears in the first term of [Eq. (2.15)](#2-15); a similar statement holds for the second term of [Eq. (2.15)](#2-15) and the first term of [Eq. (2.16)](#2-16).

We introduce the notation  

<span type="math display" id="leftrightfun">
 \begin{equation}
  \mathop{\rm left}[j] = u - {u_{i + 1 - j}}\qquad
  \mathop{\rm right}[j] = {u_{i + j}} - u
 \notag
 \end{equation} </span>

[Eq. (2.15](#2-14)[-2.16)](#2-16) are then  

<span type="math display">
 \begin{equation}
  {N_{i - 2,2}}(u) = \frac{{{\mathop{\rm left}} [ 3 ]}}{{{\mathop{\rm right}} [ 0 ] + {\mathop{\rm left}} [ 3 ]}}{N_{i - 2,1}}(u) + \frac{{{\mathop{\rm right}} [ 1 ]}}{{{\mathop{\rm right}} [ 1 ] + {\mathop{\rm left}} [ 2 ]}}{N_{i - 1,1}}(u)
 \notag
 \end{equation} </span>

<span type="math display">
 \begin{equation}
  {N_{i - 1,2}}(u) = \frac{{{\mathop{\rm left}} [ 2 ]}}{{{\mathop{\rm right}} [ 1 ] + {\mathop{\rm left}} [ 2 ]}}{N_{i - 1,1}}(u) + \frac{{{\mathop{\rm right}} [ 2 ]}}{{{\mathop{\rm right}} [ 2 ] + {\mathop{\rm left}} [ 1 ]}}{N_{i,1}}(u)
 \notag
 \end{equation} </span>

<span type="math display">
 \begin{equation}
  {N_{i,2}}(u) = \frac{{{\mathop{\rm left}} [ 1 ]}}{{{\mathop{\rm right}} [ 2 ] + {\mathop{\rm left}} [ 1 ]}}{N_{i,1}}(u) + \frac{{{\mathop{\rm right}} [ 3 ]}}{{{\mathop{\rm right}} [ 3 ] + {\mathop{\rm left}} [ 0 ]}}{N_{i + 1,1}}(u)
 \notag
 \end{equation} </span>  

---

[^1]: Piegl, L., and Tiller, W., (1995) The NURBS Book, Springer,  Berlin, Heidelberg.

ford/project-file.md

project: minimal
src_dir: ../src/
md_base_dir: ../src_comment/
output_dir: ../doc/
sort: src
docmark: <
predocmark: >
predocmark_alt: #
display: public
         protected
         private
source: true
graph: true
search: true
preprocess: False

I've also tried the latest commits 9f6d8e4e658e118bd8b9d6db690bbeaa3401375e and d072cc7 for my project, however it comes up with the following error

Traceback (most recent call last):
  File "C:\Users\tuncaen\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\tuncaen\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\Users\tuncaen\AppData\Local\Programs\Python\Python310\Scripts\ford.exe\__main__.py", line 7, in <module>
  File "C:\Users\tuncaen\src\ford\ford\__init__.py", line 491, in run
    main(proj_data, proj_docs)
  File "C:\Users\tuncaen\src\ford\ford\__init__.py", line 419, in main
    project.correlate()
  File "C:\Users\tuncaen\src\ford\ford\fortran_project.py", line 361, in correlate
    container.correlate(self)
  File "C:\Users\tuncaen\src\ford\ford\sourceform.py", line 1292, in correlate
    entity.correlate(project)
  File "C:\Users\tuncaen\src\ford\ford\sourceform.py", line 1257, in correlate
    item = self._find_chain_item(call)
  File "C:\Users\tuncaen\src\ford\ford\sourceform.py", line 1487, in _find_chain_item
    return get_label_item(context, call_chain[-1])
  File "C:\Users\tuncaen\src\ford\ford\sourceform.py", line 1449, in get_label_item
    labels[extend_type.name.lower()] = extend_type
AttributeError: 'str' object has no attribute 'name'

Thanks in advance, and thank you for continuing to develop this library Kind regards.

ZedThree commented 10 months ago

Hi @tuncaen, no worries! I've double checked with your example, and I can confirm that it will be fixed in ford v7.0.0, which will be released very soon!