Esempio n. 1
0
static void get_xlatoms(const char *fn,FILE *fp,
                        int *nptr,t_xlate_atom **xlptr)
{
    char filebase[STRLEN];
    char line[STRLEN];
    char rbuf[1024],abuf[1024],repbuf[1024],dumbuf[1024];
    char *_ptr;
    int  n,na,idum;
    t_xlate_atom *xl;

    fflib_filename_base(fn,filebase,STRLEN);

    n  = *nptr;
    xl = *xlptr;

    while (get_a_line(fp,line,STRLEN))
    {
        na = sscanf(line,"%s%s%s%s",rbuf,abuf,repbuf,dumbuf);
        /* Check if we are reading an old format file with the number of items
         * on the first line.
         */
        if (na == 1 && n == *nptr && sscanf(rbuf,"%d",&idum) == 1)
        {
            continue;
        }
        if (na != 3)
        {
            gmx_fatal(FARGS,"Expected a residue name and two atom names in file '%s', not '%s'",fn,line);
        }
        
        srenew(xl,n+1);
        xl[n].filebase = strdup(filebase);

        /* Use wildcards... */
        if (strcmp(rbuf,"*") != 0)
        {
            xl[n].res = strdup(rbuf);
        }
        else
        {
            xl[n].res = NULL;
        }
        
        /* Replace underscores in the string by spaces */
        while ((_ptr = strchr(abuf,'_')) != 0)
        {
            *_ptr = ' ';
        }
        
        xl[n].atom = strdup(abuf);
        xl[n].replace = strdup(repbuf);
        n++;
    }

    *nptr  = n;
    *xlptr = xl;
}
Esempio n. 2
0
void read_resall(char *rrdb, int *nrtpptr, t_restp **rtp,
                 gpp_atomtype_t atype, t_symtab *tab,
                 gmx_bool bAllowOverrideRTP)
{
    FILE         *in;
    char          filebase[STRLEN], line[STRLEN], header[STRLEN];
    int           i, nrtp, maxrtp, bt, nparam;
    int           dum1, dum2, dum3;
    t_restp      *rrtp, *header_settings;
    gmx_bool      bNextResidue, bError;
    int           firstrtp;

    fflib_filename_base(rrdb, filebase, STRLEN);

    in = fflib_open(rrdb);

    if (debug)
    {
        fprintf(debug, "%9s %5s", "Residue", "atoms");
        for (i = 0; i < ebtsNR; i++)
        {
            fprintf(debug, " %10s", btsNames[i]);
        }
        fprintf(debug, "\n");
    }
    snew(header_settings, 1);

    /* these bonded parameters will overwritten be when  *
     * there is a [ bondedtypes ] entry in the .rtp file */
    header_settings->rb[ebtsBONDS].type  = 1; /* normal bonds     */
    header_settings->rb[ebtsANGLES].type = 1; /* normal angles    */
    header_settings->rb[ebtsPDIHS].type  = 1; /* normal dihedrals */
    header_settings->rb[ebtsIDIHS].type  = 2; /* normal impropers */
    header_settings->rb[ebtsEXCLS].type  = 1; /* normal exclusions */
    header_settings->rb[ebtsCMAP].type   = 1; /* normal cmap torsions */

    header_settings->bKeepAllGeneratedDihedrals    = FALSE;
    header_settings->nrexcl                        = 3;
    header_settings->bGenerateHH14Interactions     = TRUE;
    header_settings->bRemoveDihedralIfWithImproper = TRUE;

    /* Column 5 & 6 aren't really bonded types, but we include
     * them here to avoid introducing a new section:
     * Column 5 : This controls the generation of dihedrals from the bonding.
     *            All possible dihedrals are generated automatically. A value of
     *            1 here means that all these are retained. A value of
     *            0 here requires generated dihedrals be removed if
     *              * there are any dihedrals on the same central atoms
     *                specified in the residue topology, or
     *              * there are other identical generated dihedrals
     *                sharing the same central atoms, or
     *              * there are other generated dihedrals sharing the
     *                same central bond that have fewer hydrogen atoms
     * Column 6: Number of bonded neighbors to exclude.
     * Column 7: Generate 1,4 interactions between two hydrogen atoms
     * Column 8: Remove proper dihedrals if centered on the same bond
     *           as an improper dihedral
     */
    get_a_line(in, line, STRLEN);
    if (!get_header(line, header))
    {
        gmx_fatal(FARGS, "in .rtp file at line:\n%s\n", line);
    }
    if (gmx_strncasecmp("bondedtypes", header, 5) == 0)
    {
        get_a_line(in, line, STRLEN);
        if ((nparam = sscanf(line, "%d %d %d %d %d %d %d %d",
                             &header_settings->rb[ebtsBONDS].type, &header_settings->rb[ebtsANGLES].type,
                             &header_settings->rb[ebtsPDIHS].type, &header_settings->rb[ebtsIDIHS].type,
                             &dum1, &header_settings->nrexcl, &dum2, &dum3)) < 4)
        {
            gmx_fatal(FARGS, "need 4 to 8 parameters in the header of .rtp file %s at line:\n%s\n", rrdb, line);
        }
        header_settings->bKeepAllGeneratedDihedrals    = (dum1 != 0);
        header_settings->bGenerateHH14Interactions     = (dum2 != 0);
        header_settings->bRemoveDihedralIfWithImproper = (dum3 != 0);
        get_a_line(in, line, STRLEN);
        if (nparam < 5)
        {
            fprintf(stderr, "Using default: not generating all possible dihedrals\n");
            header_settings->bKeepAllGeneratedDihedrals = FALSE;
        }
        if (nparam < 6)
        {
            fprintf(stderr, "Using default: excluding 3 bonded neighbors\n");
            header_settings->nrexcl = 3;
        }
        if (nparam < 7)
        {
            fprintf(stderr, "Using default: generating 1,4 H--H interactions\n");
            header_settings->bGenerateHH14Interactions = TRUE;
        }
        if (nparam < 8)
        {
            fprintf(stderr, "Using default: removing proper dihedrals found on the same bond as a proper dihedral\n");
            header_settings->bRemoveDihedralIfWithImproper = TRUE;
        }
    }
    else
    {
        fprintf(stderr,
                "Reading .rtp file without '[ bondedtypes ]' directive,\n"
                "Will proceed as if the entry was:\n");
        print_resall_header(stderr, header_settings);
    }
    /* We don't know the current size of rrtp, but simply realloc immediately */
    nrtp   = *nrtpptr;
    rrtp   = *rtp;
    maxrtp = nrtp;
    while (!feof(in))
    {
        if (nrtp >= maxrtp)
        {
            maxrtp += 100;
            srenew(rrtp, maxrtp);
        }

        /* Initialise rtp entry structure */
        rrtp[nrtp] = *header_settings;
        if (!get_header(line, header))
        {
            gmx_fatal(FARGS, "in .rtp file at line:\n%s\n", line);
        }
        rrtp[nrtp].resname  = gmx_strdup(header);
        rrtp[nrtp].filebase = gmx_strdup(filebase);

        get_a_line(in, line, STRLEN);
        bError       = FALSE;
        bNextResidue = FALSE;
        do
        {
            if (!get_header(line, header))
            {
                bError = TRUE;
            }
            else
            {
                bt = get_bt(header);
                if (bt != NOTSET)
                {
                    /* header is an bonded directive */
                    bError = !read_bondeds(bt, in, line, &rrtp[nrtp]);
                }
                else if (gmx_strncasecmp("atoms", header, 5) == 0)
                {
                    /* header is the atoms directive */
                    bError = !read_atoms(in, line, &(rrtp[nrtp]), tab, atype);
                }
                else
                {
                    /* else header must be a residue name */
                    bNextResidue = TRUE;
                }
            }
            if (bError)
            {
                gmx_fatal(FARGS, "in .rtp file in residue %s at line:\n%s\n",
                          rrtp[nrtp].resname, line);
            }
        }
        while (!feof(in) && !bNextResidue);

        if (rrtp[nrtp].natom == 0)
        {
            gmx_fatal(FARGS, "No atoms found in .rtp file in residue %s\n",
                      rrtp[nrtp].resname);
        }
        if (debug)
        {
            fprintf(debug, "%3d %5s %5d",
                    nrtp+1, rrtp[nrtp].resname, rrtp[nrtp].natom);
            for (i = 0; i < ebtsNR; i++)
            {
                fprintf(debug, " %10d", rrtp[nrtp].rb[i].nb);
            }
            fprintf(debug, "\n");
        }

        firstrtp = -1;
        for (i = 0; i < nrtp; i++)
        {
            if (gmx_strcasecmp(rrtp[i].resname, rrtp[nrtp].resname) == 0)
            {
                firstrtp = i;
            }
        }

        if (firstrtp == -1)
        {
            nrtp++;
            fprintf(stderr, "\rResidue %d", nrtp);
            fflush(stderr);
        }
        else
        {
            if (firstrtp >= *nrtpptr)
            {
                gmx_fatal(FARGS, "Found a second entry for '%s' in '%s'",
                          rrtp[nrtp].resname, rrdb);
            }
            if (bAllowOverrideRTP)
            {
                fprintf(stderr, "\n");
                fprintf(stderr, "Found another rtp entry for '%s' in '%s', ignoring this entry and keeping the one from '%s.rtp'\n",
                        rrtp[nrtp].resname, rrdb, rrtp[firstrtp].filebase);
                /* We should free all the data for this entry.
                 * The current code gives a lot of dangling pointers.
                 */
                clear_t_restp(&rrtp[nrtp]);
            }
            else
            {
                gmx_fatal(FARGS, "Found rtp entries for '%s' in both '%s' and '%s'. If you want the first definition to override the second one, set the -rtpo option of pdb2gmx.", rrtp[nrtp].resname, rrtp[firstrtp].filebase, rrdb);
            }
        }
    }
    gmx_ffclose(in);
    /* give back unused memory */
    srenew(rrtp, nrtp);

    fprintf(stderr, "\nSorting it all out...\n");
    qsort(rrtp, nrtp, (size_t)sizeof(rrtp[0]), comprtp);

    check_rtp(nrtp, rrtp, rrdb);

    *nrtpptr = nrtp;
    *rtp     = rrtp;
}
Esempio n. 3
0
void read_resall(char *rrdb, int *nrtpptr, t_restp **rtp, 
                 gpp_atomtype_t atype, t_symtab *tab,
                 gmx_bool bAllowOverrideRTP)
{
  FILE      *in;
  char      filebase[STRLEN],*ptr,line[STRLEN],header[STRLEN];
  int       i,nrtp,maxrtp,bt,nparam;
  int       dum1,dum2,dum3;
  t_restp   *rrtp;
  gmx_bool      bNextResidue,bError;
  int       bts[ebtsNR];
  gmx_bool      bAlldih;
  int       nrexcl;
  gmx_bool      HH14;
  gmx_bool      bRemoveDih;
  int       firstrtp;

  fflib_filename_base(rrdb,filebase,STRLEN);

  in = fflib_open(rrdb);
  
  if (debug) {
    fprintf(debug,"%9s %5s", "Residue", "atoms");
    for(i=0; i<ebtsNR; i++)
      fprintf(debug," %10s",btsNames[i]);
    fprintf(debug,"\n");
  }

  /* these bonded parameters will overwritten be when  *
   * there is a [ bondedtypes ] entry in the .rtp file */
  bts[ebtsBONDS]  = 1; /* normal bonds     */
  bts[ebtsANGLES] = 1; /* normal angles    */
  bts[ebtsPDIHS]  = 1; /* normal dihedrals */
  bts[ebtsIDIHS]  = 2; /* normal impropers */
  bts[ebtsEXCLS]  = 1; /* normal exclusions */
  bts[ebtsCMAP]   = 1; /* normal cmap torsions */

  bAlldih    = FALSE;
  nrexcl     = 3;
  HH14       = TRUE;
  bRemoveDih = TRUE;
  
  /* Column 5 & 6 aren't really bonded types, but we include
   * them here to avoid introducing a new section:
   * Column 5: 1 means generate all dihedrals, 0 not.
   * Column 6: Number of bonded neighbors to exclude.
   * Coulmn 7: Generate 1,4 interactions between pairs of hydrogens
   * Column 8: Remove impropers over the same bond as a proper dihedral
   */
  
  get_a_line(in,line,STRLEN);
  if (!get_header(line,header))
    gmx_fatal(FARGS,"in .rtp file at line:\n%s\n",line);
  if (gmx_strncasecmp("bondedtypes",header,5)==0) {
    get_a_line(in,line,STRLEN);
    if ((nparam=sscanf(line,"%d %d %d %d %d %d %d %d",
		       &bts[ebtsBONDS],&bts[ebtsANGLES],
		       &bts[ebtsPDIHS],&bts[ebtsIDIHS],
		       &dum1,&nrexcl,&dum2,&dum3)) < 4 )
    {
      gmx_fatal(FARGS,"need at least 4 (up to 8) parameters in .rtp file at line:\n%s\n",line);
    }
    bAlldih    = (dum1 != 0);
    HH14       = (dum2 != 0);
    bRemoveDih = (dum3 != 0);
    get_a_line(in,line,STRLEN);
    if(nparam<5) {
      fprintf(stderr,"Using default: not generating all possible dihedrals\n");
      bAlldih = FALSE;
    }
    if(nparam<6) {
      fprintf(stderr,"Using default: excluding 3 bonded neighbors\n");
      nrexcl = 3;
    }
    if(nparam<7) {
      fprintf(stderr,"Using default: generating 1,4 H--H interactions\n");
      HH14 = TRUE;
    }
    if(nparam<8) {
      fprintf(stderr,"Using default: removing impropers on same bond as a proper\n");
      bRemoveDih = TRUE;
    }
  } else {
    fprintf(stderr,
	    "Reading .rtp file without '[ bondedtypes ]' directive,\n"
	    "Will proceed as if the entry\n"
	    "\n"
	    "\n[ bondedtypes ]"
	    "\n; bonds  angles  dihedrals  impropers all_dihedrals nr_exclusions HH14 remove_dih"
	    "\n   %3d     %3d        %3d        %3d           %3d           %3d   %3d    %3d"
	    "\n"
	    "was present at the beginning of %s",
	    bts[0],bts[1],bts[2],bts[3], bAlldih ? 1 : 0,nrexcl,HH14,bRemoveDih,rrdb);
  }
  /* We don't know the current size of rrtp, but simply realloc immediately */
  nrtp = *nrtpptr;
  rrtp = *rtp;
  maxrtp = nrtp;
  while (!feof(in)) {
    if (nrtp >= maxrtp) {
      maxrtp+=100;
      srenew(rrtp,maxrtp);
    }
    clear_t_restp(&rrtp[nrtp]);
    if (!get_header(line,header))
      gmx_fatal(FARGS,"in .rtp file at line:\n%s\n",line);
    rrtp[nrtp].resname  = strdup(header);
    rrtp[nrtp].filebase = strdup(filebase);

    /* Set the bonded types */
    rrtp[nrtp].bAlldih    = bAlldih;
    rrtp[nrtp].nrexcl     = nrexcl;
    rrtp[nrtp].HH14       = HH14;
    rrtp[nrtp].bRemoveDih = bRemoveDih;
    for(i=0; i<ebtsNR; i++) {
      rrtp[nrtp].rb[i].type = bts[i];
    }

    get_a_line(in,line,STRLEN);
    bError=FALSE;
    bNextResidue=FALSE;
    do {
      if (!get_header(line,header)) {
	bError = TRUE;
      } else {
	bt = get_bt(header);
	if (bt != NOTSET) {
	  /* header is an bonded directive */
	  bError = !read_bondeds(bt,in,line,&rrtp[nrtp]);
	} else if (gmx_strncasecmp("atoms",header,5) == 0) {
	  /* header is the atoms directive */
	  bError = !read_atoms(in,line,&(rrtp[nrtp]),tab,atype);
	} else {
	  /* else header must be a residue name */
	  bNextResidue = TRUE;
	}
      }
      if (bError)
	gmx_fatal(FARGS,"in .rtp file in residue %s at line:\n%s\n",
		    rrtp[nrtp].resname,line);
    } while (!feof(in) && !bNextResidue);

    if (rrtp[nrtp].natom == 0)
      gmx_fatal(FARGS,"No atoms found in .rtp file in residue %s\n",
		  rrtp[nrtp].resname);
    if (debug) {
      fprintf(debug,"%3d %5s %5d",
	      nrtp+1,rrtp[nrtp].resname,rrtp[nrtp].natom);
      for(i=0; i<ebtsNR; i++)
	fprintf(debug," %10d",rrtp[nrtp].rb[i].nb);
      fprintf(debug,"\n");
    }
    
    firstrtp = -1;
    for(i=0; i<nrtp; i++) {
        if (gmx_strcasecmp(rrtp[i].resname,rrtp[nrtp].resname) == 0) {
            firstrtp = i;
        }
    }
    
    if (firstrtp == -1) {
        nrtp++;
        fprintf(stderr,"\rResidue %d",nrtp);
    } else {
        if (firstrtp >= *nrtpptr)
        {
            gmx_fatal(FARGS,"Found a second entry for '%s' in '%s'",
                      rrtp[nrtp].resname,rrdb);
        }
        if (bAllowOverrideRTP)
        {
            fprintf(stderr,"\n");
            fprintf(stderr,"Found another rtp entry for '%s' in '%s', ignoring this entry and keeping the one from '%s.rtp'\n",
                    rrtp[nrtp].resname,rrdb,rrtp[firstrtp].filebase);
            /* We should free all the data for this entry.
             * The current code gives a lot of dangling pointers.
             */
            clear_t_restp(&rrtp[nrtp]);
        }
        else
        {
            gmx_fatal(FARGS,"Found rtp entries for '%s' in both '%s' and '%s'. If you want the first definition to override the second one, set the -rtpo option of pdb2gmx.",rrtp[nrtp].resname,rrtp[firstrtp].filebase,rrdb);
        }
    }
  }
  ffclose(in);
  /* give back unused memory */
  srenew(rrtp,nrtp);
  
  fprintf(stderr,"\nSorting it all out...\n");
  qsort(rrtp,nrtp,(size_t)sizeof(rrtp[0]),comprtp);
  
  check_rtp(nrtp,rrtp,rrdb);

  *nrtpptr = nrtp;
  *rtp     = rrtp;
}
Esempio n. 4
0
static void read_h_db_file(const char *hfn,int *nahptr,t_hackblock **ah)
{	
  FILE   *in;
  char   filebase[STRLEN],line[STRLEN], buf[STRLEN];
  int    i, n, nab, nah;
  t_hackblock *aah;

  if (debug) fprintf(debug,"Hydrogen Database (%s):\n",hfn);

  fflib_filename_base(hfn,filebase,STRLEN);
  /* Currently filebase is read and set, but not used.
   * hdb entries from any hdb file and be applied to rtp entries
   * in any rtp file.
   */

  in = fflib_open(hfn);

  nah = *nahptr;
  aah = *ah;
  while (fgets2(line,STRLEN-1,in)) {
    if (sscanf(line,"%s%n",buf,&n) != 1) {
      fprintf(stderr,"Error in hdb file: nah = %d\nline = '%s'\n",
	      nah,line);
      break;
    }
    if (debug) fprintf(debug,"%s",buf);
    srenew(aah,nah+1);
    clear_t_hackblock(&aah[nah]);
    aah[nah].name     = strdup(buf);
    aah[nah].filebase = strdup(filebase);
    
    if (sscanf(line+n,"%d",&nab) == 1) {
      if (debug) fprintf(debug,"  %d\n",nab);
      snew(aah[nah].hack,nab);
      aah[nah].nhack = nab;
      for(i=0; (i<nab); i++) {
	if (feof(in))
	  gmx_fatal(FARGS, "Expected %d lines of hydrogens, found only %d "
		      "while reading Hydrogen Database %s residue %s",
		      nab, i-1, aah[nah].name, hfn);
	if(NULL==fgets(buf, STRLEN, in))
        {
	  gmx_fatal(FARGS,"Error reading from file %s",hfn);
	}
	read_ab(buf,hfn,&(aah[nah].hack[i]));
      }
    }
    nah++;
  }
  ffclose(in);
  
  /* Sort the list (necessary to be able to use bsearch */
  qsort(aah,nah,(size_t)sizeof(**ah),compaddh);

  /*
  if (debug)
    dump_h_db(hfn,nah,aah);
  */
  
  *nahptr = nah;
  *ah     = aah;
}
Esempio n. 5
0
static void read_ter_db_file(const char *fn,
                             int *ntbptr, t_hackblock **tbptr,
                             gpp_atomtype_t atype)
{
    char         filebase[STRLEN], *ptr;
    FILE        *in;
    char         header[STRLEN], buf[STRLEN], line[STRLEN];
    t_hackblock *tb;
    int          i, j, n, ni, kwnr, nb, maxnb, nh;

    fflib_filename_base(fn, filebase, STRLEN);
    /* Remove the C/N termini extension */
    ptr = strrchr(filebase, '.');
    if (ptr != nullptr)
    {
        ptr[0] = '\0';
    }

    in = fflib_open(fn);

    tb    = *tbptr;
    nb    = *ntbptr - 1;
    maxnb = 0;
    kwnr  = NOTSET;
    get_a_line(in, line, STRLEN);
    while (!feof(in))
    {
        if (get_header(line, header))
        {
            /* this is a new block, or a new keyword */
            kwnr = find_kw(header);

            if (kwnr == NOTSET)
            {
                nb++;
                /* here starts a new block */
                if (nb >= maxnb)
                {
                    maxnb = nb + 100;
                    srenew(tb, maxnb);
                }
                clear_t_hackblock(&tb[nb]);
                tb[nb].name     = gmx_strdup(header);
                tb[nb].filebase = gmx_strdup(filebase);
            }
        }
        else
        {
            if (nb < 0)
            {
                gmx_fatal(FARGS, "reading termini database: "
                          "directive expected before line:\n%s\n"
                          "This might be a file in an old format.", line);
            }
            /* this is not a header, so it must be data */
            if (kwnr >= ebtsNR)
            {
                /* this is a hack: add/rename/delete atoms */
                /* make space for hacks */
                if (tb[nb].nhack >= tb[nb].maxhack)
                {
                    tb[nb].maxhack += 10;
                    srenew(tb[nb].hack, tb[nb].maxhack);
                }
                nh = tb[nb].nhack;
                clear_t_hack(&(tb[nb].hack[nh]));
                for (i = 0; i < 4; i++)
                {
                    tb[nb].hack[nh].a[i] = nullptr;
                }
                tb[nb].nhack++;

                /* get data */
                n = 0;
                if (kwnr == ekwRepl || kwnr == ekwDel)
                {
                    if (sscanf(line, "%s%n", buf, &n) != 1)
                    {
                        gmx_fatal(FARGS, "Reading Termini Database '%s': "
                                  "expected atom name on line\n%s", fn, line);
                    }
                    tb[nb].hack[nh].oname = gmx_strdup(buf);
                    /* we only replace or delete one atom at a time */
                    tb[nb].hack[nh].nr = 1;
                }
                else if (kwnr == ekwAdd)
                {
                    read_ab(line, fn, &(tb[nb].hack[nh]));
                    get_a_line(in, line, STRLEN);
                }
                else
                {
                    gmx_fatal(FARGS, "unimplemented keyword number %d (%s:%d)",
                              kwnr, __FILE__, __LINE__);
                }
                if (kwnr == ekwRepl || kwnr == ekwAdd)
                {
                    snew(tb[nb].hack[nh].atom, 1);
                    read_atom(line+n, kwnr == ekwAdd,
                              &tb[nb].hack[nh].nname, tb[nb].hack[nh].atom, atype,
                              &tb[nb].hack[nh].cgnr);
                    if (tb[nb].hack[nh].nname == nullptr)
                    {
                        if (tb[nb].hack[nh].oname != nullptr)
                        {
                            tb[nb].hack[nh].nname = gmx_strdup(tb[nb].hack[nh].oname);
                        }
                        else
                        {
                            gmx_fatal(FARGS, "Reading Termini Database '%s': don't know which name the new atom should have on line\n%s", fn, line);
                        }
                    }
                }
            }
            else if (kwnr >= 0 && kwnr < ebtsNR)
            {
                /* this is bonded data: bonds, angles, dihedrals or impropers */
                srenew(tb[nb].rb[kwnr].b, tb[nb].rb[kwnr].nb+1);
                n = 0;
                for (j = 0; j < btsNiatoms[kwnr]; j++)
                {
                    if (sscanf(line+n, "%s%n", buf, &ni) == 1)
                    {
                        tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].a[j] = gmx_strdup(buf);
                    }
                    else
                    {
                        gmx_fatal(FARGS, "Reading Termini Database '%s': expected %d atom names (found %d) on line\n%s", fn, btsNiatoms[kwnr], j-1, line);
                    }
                    n += ni;
                }
                for (; j < MAXATOMLIST; j++)
                {
                    tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].a[j] = nullptr;
                }
                strcpy(buf, "");
                sscanf(line+n, "%s", buf);
                tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].s = gmx_strdup(buf);
                tb[nb].rb[kwnr].nb++;
            }
            else
            {
                gmx_fatal(FARGS, "Reading Termini Database: Expecting a header at line\n"
                          "%s", line);
            }
        }
        get_a_line(in, line, STRLEN);
    }
    nb++;
    srenew(tb, nb);

    gmx_ffclose(in);

    *ntbptr = nb;
    *tbptr  = tb;
}