Actual source code: yamlimpls.c

petsc-3.14.6 2021-03-30
Report Typos and Errors
  1: #include <petsc/private/petscimpl.h>
  2: #include <yaml.h>

  4: enum storage_flags {VAR,VAL,SEQ};     /* "Store as" switch */

  6: static PetscErrorCode PetscParseLayerYAML(PetscOptions options, yaml_document_t *doc, yaml_node_t *node)
  7: {
  8:   char            option[PETSC_MAX_PATH_LEN],prefix[PETSC_MAX_PATH_LEN];
  9:   yaml_node_pair_t *start, *top;
 10:   PetscErrorCode  ierr;

 13:   PetscSNPrintf(option,PETSC_MAX_PATH_LEN,"%s"," ");
 14:   if (node->type != YAML_MAPPING_NODE) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported yaml node type: expected mapping");
 15:   start = node->data.mapping.pairs.start;
 16:   top   = node->data.mapping.pairs.top;
 17:   for (yaml_node_pair_t *pair = start; pair < top; pair++) {
 18:     int key_id = pair->key;
 19:     int value_id = pair->value;
 20:     yaml_node_t *key = NULL;
 21:     yaml_node_t *value = NULL;

 23:     key = yaml_document_get_node(doc, key_id);
 24:     if (!key) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_LIB, "Corrupt yaml document");
 25:     value = yaml_document_get_node(doc, value_id);
 26:     if (!value) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_LIB, "Corrupt yaml document");
 27:     if (key->type != YAML_SCALAR_NODE) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported yaml node type: expected scalar");
 28:     if (value->type == YAML_SCALAR_NODE) {
 29:       PetscSNPrintf(option,PETSC_MAX_PATH_LEN,"-%s %s",(char *)(key->data.scalar.value),(char*)(value->data.scalar.value));
 30:       PetscOptionsInsertString(options, option);
 31:     } else if (value->type == YAML_MAPPING_NODE) {
 32:       PetscBool isMerge;

 34:       /* "<<" is the merge key: don't increment the prefix */
 35:       PetscStrcmp((char *)(key->data.scalar.value), "<<", &isMerge);
 36:       if (!isMerge) {
 37:         PetscSNPrintf(prefix,PETSC_MAX_PATH_LEN,"%s_",(char *)(key->data.scalar.value));
 38:         PetscOptionsPrefixPush(options, prefix);
 39:       }
 40:       PetscParseLayerYAML(options, doc, value);
 41:       if (!isMerge) {
 42:         PetscOptionsPrefixPop(options);
 43:       }
 44:     } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported yaml node tye: expected scalar or mapping");
 45:   }
 46:   return(0);
 47: }

 49: /*@C
 50:    PetscOptionsInsertStringYAML - Inserts YAML-formatted options into the database from a string

 52:    Logically Collective

 54:    Input Parameter:
 55: +  options - options object
 56: -  in_str - YAML-formatted string op options

 58:    Level: intermediate

 60: .seealso: PetscOptionsSetValue(), PetscOptionsView(), PetscOptionsHasName(), PetscOptionsGetInt(),
 61:           PetscOptionsGetReal(), PetscOptionsGetString(), PetscOptionsGetIntArray(), PetscOptionsBool(),
 62:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
 63:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
 64:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
 65:           PetscOptionsFList(), PetscOptionsEList(), PetscOptionsInsertFile(), PetscOptionsInsertFileYAML()
 66: @*/
 67: PetscErrorCode PetscOptionsInsertStringYAML(PetscOptions options,const char in_str[])
 68: {
 70:   size_t         yamlLength;
 71:   yaml_parser_t  parser;
 72:   yaml_document_t doc;
 73:   yaml_node_t    *root = NULL;

 76:   PetscStrlen(in_str, &yamlLength);
 77:   if (!yaml_parser_initialize(&parser)){
 78:     SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_LIB,"YAML parser initialization error");
 79:   }
 80:   yaml_parser_set_input_string(&parser,(const unsigned char *) in_str,yamlLength);
 81:   if (!yaml_parser_load(&parser, &doc)) {
 82:     SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_LIB,"YAML parser loading error");
 83:   }
 84:   root = yaml_document_get_root_node(&doc);
 85:   if (root) {
 86:     PetscParseLayerYAML(options, &doc, root);
 87:   }
 88:   yaml_document_delete(&doc);
 89:   yaml_parser_delete(&parser);
 90:   return(0);
 91: }

 93: /*@C

 95:   PetscOptionsInsertFileYAML - Insert a YAML-formatted file in the option database

 97:   Collective

 99:   Input Parameter:
100: +   comm - the processes that will share the options (usually PETSC_COMM_WORLD)
101: .   file - name of file
102: -   require - if PETSC_TRUE will generate an error if the file does not exist

104:   Only a small subset of the YAML standard is implemented. Sequences are NOT supported;
105:   aliases and the merge key "<<" are.
106:   The algorithm recursively parses the yaml file, pushing and popping prefixes
107:   and inserting key + values pairs using PetscOptionsInsertString().

109:   PETSc will generate an error condition that stops the program if a YAML error
110:   is detected, hence the user should check that the YAML file is valid before
111:   supplying it, for instance at http://www.yamllint.com/ .

113:   Inspired by https://stackoverflow.com/a/621451

115:   Level: intermediate

117: .seealso: PetscOptionsSetValue(), PetscOptionsView(), PetscOptionsHasName(), PetscOptionsGetInt(),
118:           PetscOptionsGetReal(), PetscOptionsGetString(), PetscOptionsGetIntArray(), PetscOptionsBool(),
119:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
120:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
121:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
122:           PetscOptionsFList(), PetscOptionsEList(), PetscOptionsInsertFile(), PetscOptionsInsertStringYAML()
123: @*/
124: PetscErrorCode PetscOptionsInsertFileYAML(MPI_Comm comm,const char file[],PetscBool require)
125: {
127:   PetscMPIInt    rank;
128:   char           fname[PETSC_MAX_PATH_LEN];
129:   unsigned char *optionsStr;
130:   int            yamlLength;
131:   FILE          *source;
132:   PetscInt       offset;
133:   size_t         rd;

136:   MPI_Comm_rank(comm,&rank);
137:   if (!rank) {
138:     PetscFixFilename(file,fname);
139:     source = fopen(fname,"r");
140:     if (source) {
141:       fseek(source,0,SEEK_END);
142:       yamlLength = ftell(source);
143:       fseek(source,0,SEEK_SET);
144:       PetscMalloc1(yamlLength+1,&optionsStr);
145:       /* Read the content of the YAML file one char at a time; why does this read the file one byte at a time? */
146:       for (offset = 0; offset < yamlLength; offset++) {
147:         rd = fread(&(optionsStr[offset]), sizeof(unsigned char),1,source);
148:         if (rd != sizeof(unsigned char)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire YAML file: %s",file);
149:       }
150:       fclose(source);
151:       optionsStr[yamlLength] = '\0';
152:     } else if (require) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open YAML option file %s\n",fname);
153:     MPI_Bcast(&yamlLength,1,MPI_INT,0,comm);
154:     MPI_Bcast(optionsStr,yamlLength+1,MPI_UNSIGNED_CHAR,0,comm);
155:   } else {
156:     MPI_Bcast(&yamlLength,1,MPI_INT,0,comm);
157:     PetscMalloc1(yamlLength+1,&optionsStr);
158:     MPI_Bcast(optionsStr,yamlLength+1,MPI_UNSIGNED_CHAR,0,comm);
159:   }
160:   PetscOptionsInsertStringYAML(NULL, (const char *) optionsStr);
161:   PetscFree(optionsStr);
162:   return(0);
163: }