Repository: stan-dev/cmdstanpy

Issue:
Use universal names in example
#### Summary:

Hi, could we go with `model` and `fit` names in the example on the readme?

#### Description:

I would just want to copy and paste the example code and then just change small amount of rows so that I can easily run my code.

#### Additional Information:

```
import os
from cmdstanpy import cmdstan_path, CmdStanModel

# specify locations of Stan program file and data
stan_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
data_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.data.json')

# instantiate a model; compiles the Stan program by default
model = CmdStanModel(stan_file=stan_file)

# obtain a posterior sample from the model conditioned on the data
fit = model.sample(chains=4, data=data_file)

# summarize the results (wraps CmdStan `bin/stansummary`):
fit.summary()
```

#### Current Version:

Github

Discussion:

Patch:
diff --git a/.pylintrc b/.pylintrc
index 0d112d8..2ae00d9 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -73,9 +73,10 @@ disable=bad-continuation,
     too-many-branches,
     too-many-locals,
     unsubscriptable-object,
-    consider-using-with,
-    consider-using-dict-items,
-    unspecified-encoding,
+    consider-using-with
+
+
+
 
 # Enable the message, report, category or checker with the given id(s). You can
 # either give multiple identifier separated by comma (,) or put this option
diff --git a/README.md b/README.md
index dce0408..33634ce 100644
--- a/README.md
+++ b/README.md
@@ -37,20 +37,20 @@ The CmdStanPy, CmdStan, and the core Stan C++ code are licensed under new BSD.
 
 ### Example
 
-::
+```python
+import os
+from cmdstanpy import cmdstan_path, CmdStanModel
 
-    import os
-    from cmdstanpy import cmdstan_path, CmdStanModel
+# specify locations of Stan program file and data
+stan_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
+data_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.data.json')
 
-    # specify locations of Stan program file and data
-    bernoulli_stan = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
-    bernoulli_data = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.data.json')
+# instantiate a model; compiles the Stan program by default
+model = CmdStanModel(stan_file=stan_file)
 
-    # instantiate a model; compiles the Stan program by default
-    bernoulli_model = CmdStanModel(stan_file=bernoulli_stan)
+# obtain a posterior sample from the model conditioned on the data
+fit = model.sample(chains=4, data=data_file)
 
-    # obtain a posterior sample from the model conditioned on the data
-    bernoulli_fit = bernoulli_model.sample(chains=4, data=bernoulli_data)
-
-    # summarize the results (wraps CmdStan `bin/stansummary`):
-    bernoulli_fit.summary()
+# summarize the results (wraps CmdStan `bin/stansummary`):
+fit.summary()
+```
diff --git a/cmdstanpy/cmdstan_args.py b/cmdstanpy/cmdstan_args.py
index 6f45772..7e96f52 100644
--- a/cmdstanpy/cmdstan_args.py
+++ b/cmdstanpy/cmdstan_args.py
@@ -159,8 +159,6 @@ class SamplerArgs:
                     self.metric = 'diag_e'
                 elif self.metric in ['dense', 'dense_e']:
                     self.metric = 'dense_e'
-                elif self.metric in ['unit', 'unit_e']:
-                    self.metric = 'unit_e'
                 else:
                     if not os.path.exists(self.metric):
                         raise ValueError('no such file {}'.format(self.metric))
@@ -640,7 +638,7 @@ class CmdStanArgs:
         inits: Union[int, float, str, List[str], None] = None,
         output_dir: Optional[str] = None,
         sig_figs: Optional[int] = None,
-        save_latent_dynamics: bool = False,
+        save_diagnostics: bool = False,
         save_profile: bool = False,
         refresh: Optional[int] = None,
         logger: Optional[logging.Logger] = None,
@@ -654,7 +652,7 @@ class CmdStanArgs:
         self.inits = inits
         self.output_dir = output_dir
         self.sig_figs = sig_figs
-        self.save_latent_dynamics = save_latent_dynamics
+        self.save_diagnostics = save_diagnostics
         self.save_profile = save_profile
         self.refresh = refresh
         self.method_args = method_args
diff --git a/cmdstanpy/model.py b/cmdstanpy/model.py
index 1ac982f..a2022c6 100644
--- a/cmdstanpy/model.py
+++ b/cmdstanpy/model.py
@@ -410,7 +410,7 @@ class CmdStanModel:
         those arguments will have CmdStan default values.
 
         The :class:`CmdStanMLE` object records the command, the return code,
-        and the paths to the optimize method output CSV and console files.
+        and the paths to the optimize method output csv and console files.
         The output files are written either to a specified output directory
         or to a temporary directory which is deleted upon session exit.
 
@@ -454,7 +454,7 @@ class CmdStanModel:
             Introduced in CmdStan-2.25.
 
         :param save_profile: Whether or not to profile auto-diff operations in
-            labelled blocks of code.  If True, CSV outputs are written to a file
+            labelled blocks of code.  If True, csv outputs are written to a file
             '<model_name>-<YYYYMMDDHHMM>-profile-<chain_id>'.
             Introduced in CmdStan-2.26.
 
@@ -551,7 +551,7 @@ class CmdStanModel:
         fixed_param: bool = False,
         output_dir: Optional[str] = None,
         sig_figs: Optional[int] = None,
-        save_latent_dynamics: bool = False,
+        save_diagnostics: bool = False,
         save_profile: bool = False,
         show_progress: Union[bool, str] = False,
         refresh: Optional[int] = None,
@@ -627,7 +627,7 @@ class CmdStanModel:
             chain.
 
         :param save_warmup: When ``True``, sampler saves warmup draws as part of
-            the Stan CSV output file.
+            the Stan csv output file.
 
         :param thin: Period between recorded iterations.  Default is 1, i.e.,
              all iterations are recorded.
@@ -696,20 +696,16 @@ class CmdStanModel:
             precision for the system file I/O is used; the usual value is 6.
             Introduced in CmdStan-2.25.
 
-        :param save_latent_dynamics: Whether or not to output the position and
-            momentum information for the model parameters (unconstrained).
-            If True, CSV outputs are written to an output file using filename
+        :param save_diagnostics: Whether or not to output the position and
+            momentum information for each parameter.  If True,
+            csv outputs are written to an output file using filename
             template '<model_name>-<YYYYMMDDHHMM>-diagnostic-<chain_id>',
-            e.g. 'bernoulli-201912081451-diagnostic-1.csv', see
-            https://mc-stan.org/docs/cmdstan-guide/stan-csv.html,
-            section "Diagnostic CSV output file" for details.
+            e.g. 'bernoulli-201912081451-diagnostic-1.csv'.
 
         :param save_profile: Whether or not to profile auto-diff operations in
-            labelled blocks of code.  If True, CSV outputs are written to a file
+            labelled blocks of code.  If True, csv outputs are written to a file
             '<model_name>-<YYYYMMDDHHMM>-profile-<chain_id>'.
-            Introduced in CmdStan-2.26, see
-            https://mc-stan.org/docs/cmdstan-guide/stan-csv.html,
-            section "Profiling CSV output file" for details.
+            Introduced in CmdStan-2.26.
 
         :param show_progress: Use tqdm progress bar to show sampling progress.
             If show_progress=='notebook' use tqdm_notebook
@@ -824,7 +820,7 @@ class CmdStanModel:
                 inits=_inits,
                 output_dir=output_dir,
                 sig_figs=sig_figs,
-                save_latent_dynamics=save_latent_dynamics,
+                save_diagnostics=save_diagnostics,
                 save_profile=save_profile,
                 method_args=sampler_args,
                 refresh=refresh,
@@ -909,7 +905,7 @@ class CmdStanModel:
         method to generate additional quantities of interest.
 
         The :class:`CmdStanGQ` object records the command, the return code,
-        and the paths to the generate method output CSV and console files.
+        and the paths to the generate method output csv and console files.
         The output files are written either to a specified output directory
         or to a temporary directory which is deleted upon session exit.
 
@@ -1025,7 +1021,7 @@ class CmdStanModel:
         inits: Optional[float] = None,
         output_dir: Optional[str] = None,
         sig_figs: Optional[int] = None,
-        save_latent_dynamics: bool = False,
+        save_diagnostics: bool = False,
         save_profile: bool = False,
         algorithm: Optional[str] = None,
         iter: Optional[int] = None,
@@ -1051,7 +1047,7 @@ class CmdStanModel:
         those arguments will have CmdStan default values.
 
         The :class:`CmdStanVB` object records the command, the return code,
-        and the paths to the variational method output CSV and console files.
+        and the paths to the variational method output csv and console files.
         The output files are written either to a specified output directory
         or to a temporary directory which is deleted upon session exit.
 
@@ -1086,13 +1082,13 @@ class CmdStanModel:
             precision for the system file I/O is used; the usual value is 6.
             Introduced in CmdStan-2.25.
 
-        :param save_latent_dynamics: Whether or not to save diagnostics.
-            If True, CSV outputs are written to an output file using filename
+        :param save_diagnostics: Whether or not to save diagnostics. If True,
+            csv outputs are written to an output file using filename
             template '<model_name>-<YYYYMMDDHHMM>-diagnostic-<chain_id>',
             e.g. 'bernoulli-201912081451-diagnostic-1.csv'.
 
         :param save_profile: Whether or not to profile auto-diff operations in
-            labelled blocks of code.  If True, CSV outputs are written to a file
+            labelled blocks of code.  If True, csv outputs are written to a file
             '<model_name>-<YYYYMMDDHHMM>-profile-<chain_id>'.
             Introduced in CmdStan-2.26.
 
@@ -1148,7 +1144,7 @@ class CmdStanModel:
                 inits=_inits,
                 output_dir=output_dir,
                 sig_figs=sig_figs,
-                save_latent_dynamics=save_latent_dynamics,
+                save_diagnostics=save_diagnostics,
                 save_profile=save_profile,
                 method_args=variational_args,
                 refresh=refresh,
@@ -1242,16 +1238,11 @@ class CmdStanModel:
                     msg = 'Chain {} terminated by signal {}'.format(
                         idx + 1, proc.returncode
                     )
-                elif proc.returncode < 125:
+                else:
                     msg = 'Chain {} processing error'.format(idx + 1)
-                    msg = '{}, return code {}'.format(msg, proc.returncode)
-                elif proc.returncode > 128:
-                    msg = 'Chain {} system error'.format(idx + 1)
-                    msg = '{}, terminated by signal {}'.format(
-                        msg, proc.returncode - 128
+                    msg = '{}, non-zero return code {}'.format(
+                        msg, proc.returncode
                     )
-                else:
-                    msg = 'Chain {} unknown error'.format(idx + 1)
                 if len(console_error) > 0:
                     msg = '{}\n error message:\n\t{}'.format(msg, console_error)
                 get_logger().error(msg)
diff --git a/cmdstanpy/stanfit.py b/cmdstanpy/stanfit.py
index b789294..5f9d7eb 100644
--- a/cmdstanpy/stanfit.py
+++ b/cmdstanpy/stanfit.py
@@ -134,7 +134,7 @@ class RunSet:
             )
             self._stderr_files[i] = stderr_file
             # optional output files:  diagnostics, profiling
-            if args.save_latent_dynamics:
+            if args.save_diagnostics:
                 if args.output_dir is None:
                     diag_file = create_named_text_file(
                         dir=_TMPDIR,
@@ -168,7 +168,7 @@ class RunSet:
                         ),
                     )
                 self._profile_files[i] = profile_file
-            if args.save_latent_dynamics and args.save_profile:
+            if args.save_diagnostics and args.save_profile:
                 self._cmds.append(
                     args.compose_command(
                         i,
@@ -177,7 +177,7 @@ class RunSet:
                         profile_file=self._profile_files[i],
                     )
                 )
-            elif args.save_latent_dynamics:
+            elif args.save_diagnostics:
                 self._cmds.append(
                     args.compose_command(
                         i,
@@ -204,7 +204,7 @@ class RunSet:
             repr = '{}\n csv_files:\n\t{}'.format(
                 repr, '\n\t'.join(self._csv_files)
             )
-        if self._args.save_latent_dynamics and os.path.exists(
+        if self._args.save_diagnostics and os.path.exists(
             self._diagnostic_files[0]
         ):
             repr = '{}\n diagnostics_files:\n\t{}'.format(
@@ -324,7 +324,7 @@ class RunSet:
 
     def save_csvfiles(self, dir: Optional[str] = None) -> None:
         """
-        Moves CSV files to specified directory.
+        Moves csvfiles to specified directory.
 
         :param dir: directory path
 
@@ -346,7 +346,7 @@ class RunSet:
         for i in range(self.chains):
             if not os.path.exists(self._csv_files[i]):
                 raise ValueError(
-                    'Cannot access CSV file {}'.format(self._csv_files[i])
+                    'Cannot access csv file {}'.format(self._csv_files[i])
                 )
 
             path, filename = os.path.split(self._csv_files[i])
@@ -585,6 +585,28 @@ class CmdStanMCMC:
         """
         return self._metadata.cmdstan_config['column_names']  # type: ignore
 
+    @property
+    def num_unconstrained_params(self) -> int:
+        """
+        Count of _unconstrained_ model parameters. This is the metric size;
+        for metric `diag_e`, the length of the diagonal vector, for metric
+        `dense_e` this is the size of the full covariance matrix.
+
+        If the parameter variables in a model are
+        constrained parameter types, the number of constrained and
+        unconstrained parameters may differ.  The sampler reports the
+        constrained parameters and computes with the unconstrained parameters.
+        E.g. a model with 2 parameter variables, ``real alpha`` and
+        ``vector[3] beta`` has 4 constrained and 4 unconstrained parameters,
+        however a model with variables ``real alpha`` and ``simplex[3] beta``
+        has 4 constrained and 3 unconstrained parameters.
+        """
+        if self._is_fixed_param:
+            return 0
+        return self._metadata.cmdstan_config[  # type: ignore
+            'num_unconstrained_params'
+        ]
+
     @property
     def metric_type(self) -> Optional[str]:
         """
@@ -604,12 +626,7 @@ class CmdStanMCMC:
         """
         if self._is_fixed_param:
             return None
-        if self._metadata.cmdstan_config['metric'] == 'unit_e':
-            get_logger().info(
-                'Unit diagnonal metric, inverse mass matrix size unknown.'
-            )
-            return None
-        if self._draws.shape == (0,):
+        if self._metric.shape == (0,):
             self._assemble_draws()
         return self._metric
 
@@ -724,6 +741,7 @@ class CmdStanMCMC:
                     save_warmup=self._save_warmup,
                     thin=self._thin,
                 )
+                # pylint: disable=consider-using-dict-items
                 for key in dzero:
                     if (
                         key
@@ -768,59 +786,53 @@ class CmdStanMCMC:
             dtype=float,
             order='F',
         )
-        self._step_size = np.empty(self.chains, dtype=float)
+        if not self._is_fixed_param:
+            self._step_size = np.empty(self.chains, dtype=float)
+            if self.metric_type == 'diag_e':
+                self._metric = np.empty(
+                    (self.chains, self.num_unconstrained_params), dtype=float
+                )
+            else:
+                self._metric = np.empty(
+                    (
+                        self.chains,
+                        self.num_unconstrained_params,
+                        self.num_unconstrained_params,
+                    ),
+                    dtype=float,
+                )
         for chain in range(self.chains):
             with open(self.runset.csv_files[chain], 'r') as fd:
+                # skip initial comments, up to columns header
                 line = fd.readline().strip()
-                # read initial comments, CSV header row
                 while len(line) > 0 and line.startswith('#'):
                     line = fd.readline().strip()
+                # at columns header
                 if not self._is_fixed_param:
-                    # handle warmup draws, if any
                     if self._save_warmup:
                         for i in range(self.num_draws_warmup):
                             line = fd.readline().strip()
                             xs = line.split(',')
                             self._draws[i, chain, :] = [float(x) for x in xs]
+                    # read to adaptation msg
                     line = fd.readline().strip()
-                    if line != '# Adaptation terminated':  # shouldn't happen?
+                    if line != '# Adaptation terminated':
                         while line != '# Adaptation terminated':
                             line = fd.readline().strip()
-                    # step_size, metric (diag_e and dense_e only)
-                    line = fd.readline().strip()
+                    line = fd.readline().strip()  # step_size
                     _, step_size = line.split('=')
                     self._step_size[chain] = float(step_size.strip())
-                    if self._metadata.cmdstan_config['metric'] != 'unit_e':
-                        line = fd.readline().strip()  # metric type
-                        line = fd.readline().lstrip(' #\t')
-                        num_unconstrained_params = len(line.split(','))
-                        if chain == 0:   # can't allocate w/o num params
-                            if self.metric_type == 'diag_e':
-                                self._metric = np.empty(
-                                    (self.chains, num_unconstrained_params),
-                                    dtype=float,
-                                )
-                            else:
-                                self._metric = np.empty(
-                                    (
-                                        self.chains,
-                                        num_unconstrained_params,
-                                        num_unconstrained_params,
-                                    ),
-                                    dtype=float,
-                                )
-                        if self.metric_type == 'diag_e':
-                            xs = line.split(',')
-                            self._metric[chain, :] = [float(x) for x in xs]
-                        else:
+                    line = fd.readline().strip()  # metric header
+                    # process metric
+                    if self.metric_type == 'diag_e':
+                        line = fd.readline().lstrip(' #\t').strip()
+                        xs = line.split(',')
+                        self._metric[chain, :] = [float(x) for x in xs]
+                    else:
+                        for i in range(self.num_unconstrained_params):
+                            line = fd.readline().lstrip(' #\t').strip()
                             xs = line.split(',')
-                            self._metric[chain, 0, :] = [float(x) for x in xs]
-                            for i in range(1, num_unconstrained_params):
-                                line = fd.readline().lstrip(' #\t').strip()
-                                xs = line.split(',')
-                                self._metric[chain, i, :] = [
-                                    float(x) for x in xs
-                                ]
+                            self._metric[chain, i, :] = [float(x) for x in xs]
                 # process draws
                 for i in range(sampling_iter_start, num_draws):
                     line = fd.readline().strip()
@@ -834,7 +846,7 @@ class CmdStanMCMC:
         sig_figs: Optional[int] = None,
     ) -> pd.DataFrame:
         """
-        Run cmdstan/bin/stansummary over all output CSV files, assemble
+        Run cmdstan/bin/stansummary over all output csv files, assemble
         summary into DataFrame object; first row contains summary statistics
         for total joint log probability `lp__`, remaining rows contain summary
         statistics for all parameters, transformed parameters, and generated
@@ -918,7 +930,7 @@ class CmdStanMCMC:
 
     def diagnose(self) -> Optional[str]:
         """
-        Run cmdstan/bin/diagnose over all output CSV files.
+        Run cmdstan/bin/diagnose over all output csv files.
         Returns output of diagnose (stdout/stderr).
 
         The diagnose utility reads the outputs of all chains
@@ -1046,6 +1058,7 @@ class CmdStanMCMC:
             "stan_version": f"{meta['stan_version_major']}."
             f"{meta['stan_version_minor']}.{meta['stan_version_patch']}",
             "model": meta["model"],
+            "num_unconstrained_params": self.num_unconstrained_params,
             "num_draws_sampling": num_draws,
         }
         if inc_warmup and self._save_warmup:
@@ -1200,7 +1213,7 @@ class CmdStanMCMC:
 
     def save_csvfiles(self, dir: Optional[str] = None) -> None:
         """
-        Move output CSV files to specified directory.  If files were
+        Move output csvfiles to specified directory.  If files were
         written to the temporary session directory, clean filename.
         E.g., save 'bernoulli-201912081451-1-5nm6as7u.csv' as
         'bernoulli-201912081451-1.csv'.
@@ -1338,7 +1351,7 @@ class CmdStanMLE:
 
     def save_csvfiles(self, dir: Optional[str] = None) -> None:
         """
-        Move output CSV files to specified directory.  If files were
+        Move output csvfiles to specified directory.  If files were
         written to the temporary session directory, clean filename.
         E.g., save 'bernoulli-201912081451-1-5nm6as7u.csv' as
         'bernoulli-201912081451-1.csv'.
@@ -1406,6 +1419,7 @@ class CmdStanGQ:
                 drest = scan_generated_quantities_csv(
                     path=self.runset.csv_files[i],
                 )
+                # pylint: disable=consider-using-dict-items
                 for key in dzero:
                     if (
                         key
@@ -1748,6 +1762,9 @@ class CmdStanGQ:
             f"{sample_config['stan_version_minor']}."
             f"{sample_config['stan_version_patch']}",
             "model": sample_config["model"],
+            "num_unconstrained_params": (
+                self.mcmc_sample.num_unconstrained_params
+            ),
             "num_draws_sampling": num_draws,
         }
         if inc_warmup and sample_config['save_warmup']:
@@ -1904,7 +1921,7 @@ class CmdStanGQ:
 
     def save_csvfiles(self, dir: Optional[str] = None) -> None:
         """
-        Move output CSV files to specified directory.  If files were
+        Move output csvfiles to specified directory.  If files were
         written to the temporary session directory, clean filename.
         E.g., save 'bernoulli-201912081451-1-5nm6as7u.csv' as
         'bernoulli-201912081451-1.csv'.
@@ -2063,7 +2080,7 @@ class CmdStanVB:
 
     def save_csvfiles(self, dir: Optional[str] = None) -> None:
         """
-        Move output CSV files to specified directory.  If files were
+        Move output csvfiles to specified directory.  If files were
         written to the temporary session directory, clean filename.
         E.g., save 'bernoulli-201912081451-1-5nm6as7u.csv' as
         'bernoulli-201912081451-1.csv'.
diff --git a/cmdstanpy/utils.py b/cmdstanpy/utils.py
index 6b78be8..6d5f85b 100644
--- a/cmdstanpy/utils.py
+++ b/cmdstanpy/utils.py
@@ -573,7 +573,7 @@ def scan_sampler_csv(path: str, is_fixed_param: bool = False) -> Dict[str, Any]:
         lineno = scan_column_names(fd, dict, lineno)
         if not is_fixed_param:
             lineno = scan_warmup_iters(fd, dict, lineno)
-            lineno = scan_hmc_params(fd, dict, lineno)
+            lineno = scan_metric(fd, dict, lineno)
         lineno = scan_sampling_iters(fd, dict, lineno)
     return dict
 
@@ -768,12 +768,13 @@ def parse_stan_vars(
     return (dims_map, cols_map)
 
 
-def scan_hmc_params(
-    fd: TextIO, config_dict: Dict[str, Any], lineno: int
-) -> int:
+def scan_metric(fd: TextIO, config_dict: Dict[str, Any], lineno: int) -> int:
     """
-    Scan step size, metric from  stan_csv file comment lines.
+    Scan step size, metric from  stan_csv file comment lines,
+    set config_dict entries 'metric' and 'num_unconstrained_params'
     """
+    if 'metric' not in config_dict:
+        config_dict['metric'] = 'diag_e'
     metric = config_dict['metric']
     line = fd.readline().strip()
     lineno += 1
@@ -795,8 +796,6 @@ def scan_hmc_params(
         raise ValueError(
             'line {}: invalid step size: {}'.format(lineno, step_size)
         ) from e
-    if metric == 'unit_e':
-        return lineno
     line = fd.readline().strip()
     lineno += 1
     if not (
@@ -815,6 +814,7 @@ def scan_hmc_params(
     line = fd.readline().lstrip(' #\t')
     lineno += 1
     num_unconstrained_params = len(line.split(','))
+    config_dict['num_unconstrained_params'] = num_unconstrained_params
     if metric == 'diag_e':
         return lineno
     else:
@@ -919,7 +919,7 @@ def do_command(
         if proc.returncode != 0:  # problem, throw RuntimeError with msg
             try:
                 serror = os.strerror(proc.returncode)
-            except ValueError:
+            except ValueError as e:
                 pass
             if proc.returncode < 0:
                 msg = 'Command: {}\nterminated by signal'.format(cmd)
@@ -1158,11 +1158,6 @@ def wrap_progress_hook() -> Optional[Callable[[int, int, int], None]]:
     return download_progress_hook
 
 
-def report_signal(sig: int) -> None:
-    """Provide info for processes terminated by a system signal."""
-    print('terminated by signal: {}'.format(sig))
-
-
 class MaybeDictToFilePath:
     """Context manager for json files."""
 
@@ -1173,7 +1168,6 @@ class MaybeDictToFilePath:
         self._unlink = [False] * len(objs)
         self._paths: List[Any] = [''] * len(objs)
         i = 0
-        # pylint: disable=isinstance-second-argument-not-valid-type
         for obj in objs:
             if isinstance(obj, Mapping):
                 data_file = create_named_text_file(
diff --git a/cmdstanpy_tutorial.ipynb b/cmdstanpy_tutorial.ipynb
index 22befca..959b301 100644
--- a/cmdstanpy_tutorial.ipynb
+++ b/cmdstanpy_tutorial.ipynb
@@ -2,7 +2,6 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "# CmdStanPy Tutorial: do inference over a model conditioned on data\n",
     "\n",
@@ -41,11 +40,11 @@
     "The CmdStan interface is entirely file-based, therefore CmdStanPy manages the process of converting in-memory data structures to their file-based representation and vice versa.\n",
     "\n",
     "Each run of an inference algorithm produces one or more output files in [Stan CSV format](https://mc-stan.org/docs/cmdstan-guide/stan-csv.html), as well as the messages written to stdout and stderr.  CmdStanPy uses per-run directories to keep all files together; the location of the directory can be specified when setting up the run, or it can be specified and/or changed afterwards via the `save_csvfiles` method, common to all inference method classes."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "### Installation\n",
     "\n",
@@ -60,139 +59,139 @@
     "  + if you have a working installation of CmdStan, set environment variable `CMDSTAN` to the full path to the top-level CmdStan directory.\n",
     "  \n",
     "  + if you don't already have CmdStan installed, run Python script `install_cmdstan` which downloads and compiles the latest release from https://github.com/stan-dev/cmdstan/releases.  By default this installs the latest version of CmdStan in the location `~/.cmdstan`.  Flags -d and -v are used to specify the directory and version, respectively.\n"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "## Hello World:  Compile and run CmdStan example model `bernoulli.stan`\n",
     "\n",
     "Every CmdStan release has an `examples/bernoulli` directory which contains the Stan model and test data files.  In this example we compile the model and run the NUTS-HMC sampler to obtain the full posterior density.\n",
     "\n",
     "The `CmdStanModel` class method `sample` invokes Stan's NUTS-HMC sampler which conditions the model on the input data and returns a `CmdStanMCMC` object. The `CmdStanMCMC` object contains the set of draws from the posterior plus metadata."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "### Import CmdStanPy classes and methods"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "import os\n",
     "from cmdstanpy import cmdstan_path, CmdStanModel"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "### Compile the model"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "The CmdStanPy directory `examples/bernoulli` contains the model and data files."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "bernoulli_dir = os.path.join(cmdstan_path(), 'examples', 'bernoulli')\n",
-    "bernoulli_stan = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
-    "with open(bernoulli_stan, 'r') as f:\n",
+    "stan_file = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
+    "with open(stan_file, 'r') as f:\n",
     "    print(f.read())"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "The `CmdStanModel` object stores the filepaths of the Stan program and the compiled executable file.  By default, if no executable file is supplied, or if the timestamp on the model file is newer than the timestamp on the executable file, the model will be compiled on instantiation."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bernoulli_model = CmdStanModel(stan_file=bernoulli_stan)\n",
-    "print(bernoulli_model)"
-   ]
+    "model = CmdStanModel(stan_file=stan_file)\n",
+    "print(model)"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "### Assemble the data\n",
     "\n",
     "Input data is either a Python `Dict` with entries corresponding to input data values, or it can be a file in JSON or Rdump format.\n",
     "\n",
     "If a `Dict` is specified, CmdStanPy writes it to a temp file in JSON format."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_data = { \"N\" : 10, \"y\" : [0,1,0,0,0,0,0,0,0,1] }"
-   ]
+    "data = { \"N\" : 10, \"y\" : [0,1,0,0,0,0,0,0,0,1] }"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "In the CmdStan `examples/bernoulli` directory, there are data files in both `JSON` and `rdump` formats."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_json = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
-    "with open(bern_json, 'r') as f:\n",
+    "data_file = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
+    "with open(data_file, 'r') as f:\n",
     "    print(f.read())"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "### Do Inference\n",
     "\n",
     "The `CmdStanModel` class `sample` method runs the HMC-NUTS sampler to produce a set of draws from the posterior distribution.  By default, `sample` runs 4 sampler chains."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit = bernoulli_model.sample(data=bern_data)\n",
-    "print(bern_fit)"
-   ]
+    "fit = model.sample(data=data)\n",
+    "print(fit)"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "### Access the sample: the `CmdStanMCMC` object attributes and methods\n",
     "\n",
@@ -207,20 +206,20 @@
     "The `draws` array is created only as needed; therefore the first time that this property is accessed, CmdStanPy parses the set of csv output files, at the same time it parses the contain step size and metric information.  Depending on the size of the sample and your computing environment, this may take a few seconds or more.\n",
     "\n",
     "The numpy ndarray is stored column major format so that values for each parameter are stored contiguously in memory, likewise all draws from a chain are contiguous.  Thus the dimensions of the ndarray are arranged as follows:  (draws, chains, columns).  The draws array contains both the sampler variables and the model variables.  Sampler variables report the sampler state.  For the NUTS-HMC sampler, there are 7 reported variables, all of which end in `__`.  The example model contains a single variable `theta`."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit.draws().shape"
-   ]
+    "fit.draws().shape"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "#### Viewing the sample as a set of variables:  sampler variables and program variables\n",
     "\n",
@@ -228,28 +227,28 @@
     "    \n",
     "- `stan_variables` - dictionary mapping Stan program variables names to the draws for that variable.\n",
     "- `sampler_variables` - dictionary mapping the sampler variables names, (e.g., `lp__`) to the draws for that variable."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "%matplotlib inline\n",
     "import pandas as pd\n",
     "\n",
-    "vars = bern_fit.stan_variables()\n",
+    "vars = fit.stan_variables()\n",
     "for (k,v) in vars.items():\n",
     "    print(k, v.shape)\n",
     "\n",
-    "thetas = bern_fit.stan_variable(name='theta')\n",
+    "thetas = fit.stan_variable(var='theta')\n",
     "pd.DataFrame(data=thetas).plot.density()"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "#### Get HMC sampler tuning parameters\n",
     "\n",
@@ -258,59 +257,59 @@
     "The `CmdStanMCMC` property `step_size` property is a 1-D numpy ndarray which contains the step size used by the sampler for each chain.  This array is created at the same time as the `sample` and `metric` arrays are created.\n",
     "\n",
     "At the end of adaptation, the step size for the 4 chains in this example is:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit.step_size"
-   ]
+    "fit.step_size"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "#### metric_type, metric\n",
     "\n",
     "The `metric` property is an numpy ndarray which contains the metric used by the sampler for each chain.  This array is created at the same time as the `sample` and `step_size` arrays are created.\n",
     "\n",
     "At the end of adaptation, the metric for the 4 chains in this example is:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit.metric_type,  bern_fit.metric"
-   ]
+    "fit.metric_type,  fit.metric"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "#### Summarize the results\n",
     "\n",
     "The `CmdStanMCMC` method `summary` returns output of CmdStan `bin/stansummary` as a pandas.DataFrame which contains\n",
     "estimates of posterior means, standard deviations, Monte-Carlo standard error, effective sample size, and convergence diagnostic statistic for both the reported sampler parameters and all parameters, transformed parameters, and generated quantities variables:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit.summary()"
-   ]
+    "fit.summary()"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "#### Run sampler diagnostics\n",
     "\n",
@@ -325,23 +324,23 @@
     "    + high R-hat values\n",
     "   + See the Stan reference manual section on [posterior analysis](https://mc-stan.org/docs/reference-manual/analysis-chapter.html) for further details.\n",
     "\n"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit.diagnose()"
-   ]
+    "fit.diagnose()"
+   ],
+   "outputs": [],
+   "metadata": {}
   }
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
+   "name": "python3",
+   "display_name": "Python 3.9.5 64-bit"
   },
   "language_info": {
    "codemirror_mode": {
@@ -353,9 +352,12 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.8.5"
+   "version": "3.9.5"
+  },
+  "interpreter": {
+   "hash": "d31ce8e45781476cfd394e192e0962028add96ff436d4fd4e560a347d206b9cb"
   }
  },
  "nbformat": 4,
  "nbformat_minor": 2
-}
+}
\ No newline at end of file
diff --git a/cmdstanpy_tutorial.py b/cmdstanpy_tutorial.py
index 18547d6..3fa5c04 100644
--- a/cmdstanpy_tutorial.py
+++ b/cmdstanpy_tutorial.py
@@ -13,46 +13,46 @@ from cmdstanpy import CmdStanModel, cmdstan_path
 # ### Instantiate & compile the model
 
 bernoulli_dir = os.path.join(cmdstan_path(), 'examples', 'bernoulli')
-bernoulli_stan = os.path.join(bernoulli_dir, 'bernoulli.stan')
-with open(bernoulli_stan, 'r') as f:
+stan_file = os.path.join(bernoulli_dir, 'bernoulli.stan')
+with open(stan_file, 'r') as f:
     print(f.read())
 
-bernoulli_model = CmdStanModel(stan_file=bernoulli_stan)
-print(bernoulli_model)
+model = CmdStanModel(stan_file=stan_file)
+print(model)
 
 # ### Assemble the data
 
-bern_data = {"N": 10, "y": [0, 1, 0, 0, 0, 0, 0, 0, 0, 1]}
+data = {"N": 10, "y": [0, 1, 0, 0, 0, 0, 0, 0, 0, 1]}
 
 # In the CmdStan `examples/bernoulli` directory, there are data files in both `JSON` and `rdump` formats.
 # bern_json = os.path.join(bernoulli_dir, 'bernoulli.data.json')
 
 # ### Do Inference
 
-bern_fit = bernoulli_model.sample(data=bern_data)
-print(bern_fit)
+fit = model.sample(data=data)
+print(fit)
 
 # ### Access the sample: the `CmdStanMCMC` object attributes and methods
 
-bern_fit.draws().shape
+fit.draws().shape
 
-vars = bern_fit.stan_variables()
+vars = fit.stan_variables()
 for (k, v) in vars.items():
     print(k, v.shape)
 
-thetas = bern_fit.stan_variable(name='theta')
+thetas = fit.stan_variable(name='theta')
 pd.DataFrame(data=thetas).plot.density()
 
 # #### Get HMC sampler tuning parameters
 
-bern_fit.step_size
-bern_fit.metric_type
-bern_fit.metric
+fit.step_size
+fit.metric_type
+fit.metric
 
 # #### Summarize the results
 
-bern_fit.summary()
+fit.summary()
 
 # #### Run sampler diagnostics
 
-bern_fit.diagnose()
+fit.diagnose()
diff --git a/docsrc/examples/MCMC Sampling.ipynb b/docsrc/examples/MCMC Sampling.ipynb
index 15e17f8..400f218 100644
--- a/docsrc/examples/MCMC Sampling.ipynb
+++ b/docsrc/examples/MCMC Sampling.ipynb
@@ -2,7 +2,6 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "# MCMC Sampling\n",
     "\n",
@@ -22,11 +21,11 @@
     "to run these chains in separate processes.\n",
     "This processing can be done in parallel, up to the number of\n",
     "processor cores available."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "## Fitting a model to data\n",
     "\n",
@@ -36,112 +35,112 @@
     "[bernoulli.data.json](https://github.com/stan-dev/cmdstanpy/blob/master/test/data/bernoulli.data.json>).\n",
     "\n",
     "We instantiate a `CmdStanModel` from the Stan program file"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "import os\n",
     "from cmdstanpy.model import CmdStanModel\n",
     "from cmdstanpy.utils import cmdstan_path\n",
     "    \n",
     "bernoulli_dir = os.path.join(cmdstan_path(), 'examples', 'bernoulli')\n",
-    "bernoulli_path = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
-    "bernoulli_data = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
+    "stan_file = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
+    "data_file = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
     "\n",
     "# instantiate, compile bernoulli model\n",
-    "bernoulli_model = CmdStanModel(stan_file=bernoulli_path)"
-   ]
+    "model = CmdStanModel(stan_file=stan_file)"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "By default, the model is compiled during instantiation.  The compiled executable is created in the same directory as the program file.  If the directory already contains an executable file with a newer timestamp, the model is not recompiled.\n",
     "\n",
     "We run the sampler on the data using all default settings:  4 chains, each of which runs 1000 warmup and sampling iterations."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "# run CmdStan's sample method, returns object `CmdStanMCMC`\n",
-    "bern_fit = bernoulli_model.sample(data=bernoulli_data)"
-   ]
+    "fit = model.sample(data=data_file)"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "The `sample` method returns a `CmdStanMCMC` object, which contains:\n",
     "- metadata\n",
     "- draws\n",
     "- HMC tuning parameters `metric`, `step_size`"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "print('sampler diagnostic variables:\\n{}'.format(bern_fit.metadata.method_vars_cols.keys()))\n",
-    "print('stan model variables:\\n{}'.format(bern_fit.metadata.stan_vars_cols.keys()))"
-   ]
+    "print('sampler diagnostic variables:\\n{}'.format(fit.metadata.method_vars_cols.keys()))\n",
+    "print('stan model variables:\\n{}'.format(fit.metadata.stan_vars_cols.keys()))"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit.summary()"
-   ]
+    "fit.summary()"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "The sampling data from the fit can be accessed either as a `numpy` array or a pandas `DataFrame`:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "print(bern_fit.draws().shape)\n",
-    "bern_fit.draws_pd().head()"
-   ]
+    "print(fit.draws().shape)\n",
+    "fit.draws_pd().head()"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "Additionally, if `xarray` is installed, this data can be accessed another way:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit.draws_xr()"
-   ]
+    "fit.draws_xr()"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
-    "The ``bern_fit`` object records the command, the return code,\n",
+    "The ``fit`` object records the command, the return code,\n",
     "and the paths to the sampler output csv and console files.\n",
     "The string representation of this object displays the CmdStan commands and\n",
     "the location of the output files.\n",
@@ -152,65 +151,64 @@
     "the console messages, e.g. `bernoulli-201912081451-1.csv`. Output files\n",
     "written to the temporary directory contain an additional 8-character\n",
     "random string, e.g. `bernoulli-201912081451-1-5nm6as7u.csv`."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "bern_fit"
-   ]
+    "fit"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "The sampler output files are written to a temporary directory which\n",
     "is deleted upon session exit unless the ``output_dir`` argument is specified.\n",
     "The ``save_csvfiles`` function moves the CmdStan CSV output files\n",
     "to a specified directory without having to re-run the sampler.\n",
     "The console output files are not saved. These files are treated as ephemeral; if the sample is valid, all relevant information is recorded in the CSV files."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "## Running a data-generating model using `fixed_param=True`\n",
     "\n",
     "In this example we use the CmdStan example model\n",
-    "[bernoulli_datagen.stan](https://github.com/stan-dev/cmdstanpy/blob/master/docs/notebooks/bernoulli_datagen.stan)\n",
+    "[data_filegen.stan](https://github.com/stan-dev/cmdstanpy/blob/master/docs/notebooks/data_filegen.stan)\n",
     "to generate a simulated dataset given fixed data values."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "datagen_model = CmdStanModel(stan_file='bernoulli_datagen.stan')\n",
+    "model_datagen = CmdStanModel(stan_file='bernoulli_datagen.stan')\n",
     "datagen_data = {'N':300, 'theta':0.3}\n",
-    "sim_data = datagen_model.sample(data=datagen_data, fixed_param=True)\n",
-    "sim_data.summary()"
-   ]
+    "fit_sim = model_datagen.sample(data=datagen_data, fixed_param=True)\n",
+    "fit_sim.summary()"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "Compute, plot histogram of total successes for `N` Bernoulli trials with chance of success `theta`:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "drawset_pd = sim_data.draws_pd()\n",
+    "drawset_pd = fit_sim.draws_pd()\n",
     "drawset_pd.columns\n",
     "\n",
     "# restrict to columns over new outcomes of N Bernoulli trials\n",
@@ -219,7 +217,9 @@
     "# plot total number of successes per draw\n",
     "y_sums = y_sims.sum(axis=1)\n",
     "y_sums.astype('int32').plot.hist(range(0,datagen_data['N']+1))"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   }
  ],
  "metadata": {
@@ -243,4 +243,4 @@
  },
  "nbformat": 4,
  "nbformat_minor": 4
-}
+}
\ No newline at end of file
diff --git a/docsrc/examples/Maximum Likelihood Estimation.ipynb b/docsrc/examples/Maximum Likelihood Estimation.ipynb
index 661cead..fb6dee5 100644
--- a/docsrc/examples/Maximum Likelihood Estimation.ipynb
+++ b/docsrc/examples/Maximum Likelihood Estimation.ipynb
@@ -2,7 +2,6 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "# Maximum Likelihood Estimation\n",
     "\n",
@@ -11,11 +10,11 @@
     "a Newton optimizer, and two related quasi-Newton algorithms, BFGS and L-BFGS.\n",
     "The L-BFGS algorithm is the default optimizer.\n",
     "Newton’s method is the least efficient of the three, but has the advantage of setting its own stepsize."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "In this example we use the CmdStan example model\n",
     "[bernoulli.stan](https://github.com/stan-dev/cmdstanpy/blob/master/test/data/bernoulli.stan)\n",
@@ -32,30 +31,31 @@
     "- `optimized_params_pd`\n",
     "\n",
     "In the following example, we instantiate a model and do optimization using the default CmdStan settings:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "import os\n",
     "from cmdstanpy import CmdStanModel, cmdstan_path\n",
     "    \n",
     "bernoulli_dir = os.path.join(cmdstan_path(), 'examples', 'bernoulli')\n",
-    "bernoulli_path = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
-    "bernoulli_data = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
+    "stan_file = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
+    "data_file = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
     "\n",
     "# instantiate, compile bernoulli model\n",
-    "bernoulli_model = CmdStanModel(stan_file=bernoulli_path)\n",
+    "model = CmdStanModel(stan_file=stan_file)\n",
     "\n",
     "# run CmdStan's otpimize method, returns object `CmdStanMLE`\n",
-    "mle = bernoulli_model.optimize(data=bernoulli_data)\n",
+    "mle = model.optimize(data=data_file)\n",
     "print(mle.column_names)\n",
     "print(mle.optimized_params_dict)\n",
     "mle.optimized_params_pd"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   }
  ],
  "metadata": {
@@ -79,4 +79,4 @@
  },
  "nbformat": 4,
  "nbformat_minor": 4
-}
+}
\ No newline at end of file
diff --git a/docsrc/examples/Run Generated Quantities.ipynb b/docsrc/examples/Run Generated Quantities.ipynb
index 09fb473..87cbd79 100644
--- a/docsrc/examples/Run Generated Quantities.ipynb
+++ b/docsrc/examples/Run Generated Quantities.ipynb
@@ -45,12 +45,12 @@
     "from cmdstanpy import cmdstan_path, CmdStanModel, CmdStanMCMC, CmdStanGQ\n",
     "\n",
     "bernoulli_dir = os.path.join(cmdstan_path(), 'examples', 'bernoulli')\n",
-    "bernoulli_path = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
-    "bernoulli_data = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
+    "stan_file = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
+    "data_file = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
     "\n",
     "# instantiate, compile bernoulli model\n",
-    "bernoulli_model = CmdStanModel(stan_file=bernoulli_path)\n",
-    "print(bernoulli_model.code())"
+    "model = CmdStanModel(stan_file=stan_file)\n",
+    "print(model.code())"
    ],
    "outputs": [],
    "metadata": {}
@@ -70,7 +70,7 @@
     "# examine bernoulli data\n",
     "import ujson\n",
     "import statistics\n",
-    "with open(bernoulli_data,'r') as fp:\n",
+    "with open(data_file,'r') as fp:\n",
     "    data_dict = ujson.load(fp)\n",
     "print(data_dict)\n",
     "print('mean of y: {}'.format(statistics.mean(data_dict['y'])))"
@@ -90,7 +90,7 @@
    "execution_count": null,
    "source": [
     "# fit the model to the data\n",
-    "bern_fit = bernoulli_model.sample(data=bernoulli_data)"
+    "fit = model.sample(data=data_file)"
    ],
    "outputs": [],
    "metadata": {}
@@ -106,7 +106,7 @@
    "cell_type": "code",
    "execution_count": null,
    "source": [
-    "bern_fit.summary()"
+    "fit.summary()"
    ],
    "outputs": [],
    "metadata": {}
@@ -122,8 +122,8 @@
    "cell_type": "code",
    "execution_count": null,
    "source": [
-    "bernoulli_ppc_model = CmdStanModel(stan_file='bernoulli_ppc.stan')\n",
-    "print(bernoulli_ppc_model.code())"
+    "model_ppc = CmdStanModel(stan_file='bernoulli_ppc.stan')\n",
+    "print(model_ppc.code())"
    ],
    "outputs": [],
    "metadata": {}
@@ -131,7 +131,7 @@
   {
    "cell_type": "markdown",
    "source": [
-    "We run the `generate_quantities` method on `bernoulli_ppc` using existing sample `bern_fit` as input.  The `generate_quantities` method takes the values of `theta` in the `bern_fit` sample as the set of draws from the posterior used to generate the corresponsing `y_rep` quantities of interest.\n",
+    "We run the `generate_quantities` method on `bernoulli_ppc` using existing sample `fit` as input.  The `generate_quantities` method takes the values of `theta` in the `fit` sample as the set of draws from the posterior used to generate the corresponsing `y_rep` quantities of interest.\n",
     "\n",
     "The arguments to the `generate_quantities` method are:\n",
     " + `data`  - the data used to fit the model\n",
@@ -143,7 +143,7 @@
    "cell_type": "code",
    "execution_count": null,
    "source": [
-    "new_quantities = bernoulli_ppc_model.generate_quantities(data=bernoulli_data, mcmc_sample=bern_fit)"
+    "new_quantities = model_ppc.generate_quantities(data=data_file, mcmc_sample=fit)"
    ],
    "outputs": [],
    "metadata": {}
diff --git a/docsrc/examples/Variational Inference.ipynb b/docsrc/examples/Variational Inference.ipynb
index 8ff45d6..2ed6563 100644
--- a/docsrc/examples/Variational Inference.ipynb
+++ b/docsrc/examples/Variational Inference.ipynb
@@ -2,7 +2,6 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "#  Variational Inference in Stan\n",
     "\n",
@@ -23,11 +22,11 @@
     "the average and the median change of the ELBO.\n",
     "When this change falls below a threshold, denoted by ``tol_rel_obj``,\n",
     "the algorithm is considered to have converged."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "### Example: variational inference for model ``bernoulli.stan``\n",
     "\n",
@@ -35,30 +34,30 @@
     "`method=variational` and returns an estimate of the approximate posterior\n",
     "mean of all model parameters as well as a set of draws from this approximate\n",
     "posterior."
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "import os\n",
     "from cmdstanpy.model import CmdStanModel\n",
     "from cmdstanpy.utils import cmdstan_path\n",
     "\n",
     "bernoulli_dir = os.path.join(cmdstan_path(), 'examples', 'bernoulli')\n",
-    "bernoulli_path = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
-    "bernoulli_data = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
+    "stan_file = os.path.join(bernoulli_dir, 'bernoulli.stan')\n",
+    "data_file = os.path.join(bernoulli_dir, 'bernoulli.data.json')\n",
     "# instantiate, compile bernoulli model\n",
-    "bernoulli_model = CmdStanModel(stan_file=bernoulli_path)\n",
+    "model = CmdStanModel(stan_file=stan_file)\n",
     "# run CmdStan's variational inference method, returns object `CmdStanVB`\n",
-    "vi = bernoulli_model.variational(data=bernoulli_data)"
-   ]
+    "vi = model.variational(data=data_file)"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "The class [`CmdStanVB`](https://cmdstanpy.readthedocs.io/en/latest/api.html#stanvariational) provides the following properties to access information about the parameter names, estimated means, and the sample:\n",
     " + `column_names`\n",
@@ -66,94 +65,95 @@
     " + `variational_params_np`\n",
     " + `variational_params_pd`\n",
     " + `variational_sample`"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [],
    "source": [
     "print(vi.column_names)"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {
+    "scrolled": true
+   }
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "print(vi.variational_params_dict['theta'])"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
     "print(vi.variational_sample.shape)"
-   ]
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "These estimates are only valid if the algorithm has converged to a good\n",
     "approximation. When the algorithm fails to do so, the `variational`\n",
     "method will throw a `RuntimeError`.\n"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "fail_model = CmdStanModel(stan_file='eta_should_fail.stan')\n",
-    "vi = fail_model.variational()"
-   ]
+    "model_fail = CmdStanModel(stan_file='eta_should_fail.stan')\n",
+    "vi_fail = model_fail.variational()"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "Unless you set `require_converged=False`:"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "vi = fail_model.variational(require_converged=False)"
-   ]
+    "vi_fail = model_fail.variational(require_converged=False)"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "This lets you inspect the output to try to diagnose the issue with the model"
-   ]
+   ],
+   "metadata": {}
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
-   "outputs": [],
    "source": [
-    "vi.variational_params_dict"
-   ]
+    "vi_fail.variational_params_dict"
+   ],
+   "outputs": [],
+   "metadata": {}
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
    "source": [
     "See the [api docs](https://cmdstanpy.readthedocs.io/en/latest/api.html), section [`CmdStanModel.variational`](https://cmdstanpy.readthedocs.io/en/latest/api.html#cmdstanpy.CmdStanModel.variational) for a full description of all arguments."
-   ]
+   ],
+   "metadata": {}
   }
  ],
  "metadata": {
@@ -177,4 +177,4 @@
  },
  "nbformat": 4,
  "nbformat_minor": 4
-}
+}
\ No newline at end of file
diff --git a/docsrc/hello_world.rst b/docsrc/hello_world.rst
index 6565dd0..8d72d90 100644
--- a/docsrc/hello_world.rst
+++ b/docsrc/hello_world.rst
@@ -26,7 +26,7 @@ The model ``bernoulli.stan``  is a simple model for binary data:
 given a set of N observations of i.i.d. binary data
 `y[1] ... y[N]`, it calculates the Bernoulli chance-of-success `theta`.
 
-.. code::
+.. code:: stan
 
    data { 
       int<lower=0> N; 
@@ -53,13 +53,13 @@ The function :func:`~cmdstan_path` returns the value of this environment variabl
     from cmdstanpy import cmdstan_path, CmdStanModel
 
     # specify Stan program file 
-    bernoulli_stan = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
+    stan_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
 
     # instantiate the model; compiles the Stan program as needed.
-    bernoulli_model = CmdStanModel(stan_file=bernoulli_stan)
+    model = CmdStanModel(stan_file=stan_file)
 
     # inspect model object 
-    print(bernoulli_model)
+    print(model)
 
             
 Data inputs
@@ -101,13 +101,13 @@ to a temporary directory which is deleted when the current Python session is ter
 .. ipython:: python
 
     # specify data file
-    bernoulli_data = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.data.json')
+    data_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.data.json')
 
     # fit the model 
-    bernoulli_fit = bernoulli_model.sample(data=bernoulli_data) 
+    fit = model.sample(data=data_file) 
 
     # printing the object reports sampler commands, output files
-    print(bernoulli_fit)
+    print(fit)
 
 
 Accessing the sample
@@ -137,10 +137,10 @@ The :meth:`~CmdStanMCMC.stan_variables` method returns a Python dict over all St
 
 .. ipython:: python
 
-    bernoulli_fit.draws().shape 
-    bernoulli_fit.draws(concat_chains=True).shape 
+    fit.draws().shape 
+    fit.draws(concat_chains=True).shape 
 
-    draws_theta = bernoulli_fit.stan_variable(name='theta') 
+    draws_theta = fit.stan_variable(name='theta') 
     draws_theta.shape 
 
                         
@@ -157,7 +157,7 @@ all model parameters and quantities of interest in a pandas.DataFrame:
 
 .. ipython:: python
 
-    bernoulli_fit.summary()
+    fit.summary()
 
 CmdStan is distributed with a second posterior analysis utility
 `diagnose <https://mc-stan.org/docs/cmdstan-guide/diagnose.html>`__
@@ -168,7 +168,7 @@ The :meth:`~CmdStanMCMC.diagnose` method runs this utility and prints the output
 
 .. ipython:: python
 
-    print(bernoulli_fit.diagnose())
+    print(fit.diagnose())
 
 Managing Stan CSV files
 ^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ to a specified directory.
 .. ipython:: python
     :verbatim:
 
-    bernoulli_fit.save_csvfiles(dir='some/path')
+    fit.save_csvfiles(dir='some/path')
 
 
 .. comment
@@ -193,14 +193,14 @@ to a specified directory.
   
   .. code-block:: python
   
-      bernoulli_fit = bernoulli_model.sample(data=bernoulli_data, show_progress=True)
+      fit = model.sample(data=data_file, show_progress=True)
   
   On Jupyter Notebook environment user should use notebook version
   by using ``show_progress='notebook'``.
   
   .. code-block:: python
   
-      bernoulli_fit = bernoulli_model.sample(data=bernoulli_data, show_progress='notebook')
+      fit = model.sample(data=data_file, show_progress='notebook')
   
   To enable javascript progress bar on Jupyter Lab Notebook user needs to install
   nodejs and ipywidgets. Following the instructions in


Test patch:
diff --git a/test/test_runset.py b/test/test_runset.py
index 6c87882..f608f74 100644
--- a/test/test_runset.py
+++ b/test/test_runset.py
@@ -123,7 +123,7 @@ class RunSetTest(unittest.TestCase):
         self.assertIn('id=1', runset._cmds[0])
         self.assertIn('id=4', runset._cmds[3])
 
-    def test_save_latent_dynamics(self):
+    def test_save_diagnostics(self):
         exe = os.path.join(DATAFILES_PATH, 'bernoulli' + EXTENSION)
         jdata = os.path.join(DATAFILES_PATH, 'bernoulli.data.json')
         sampler_args = SamplerArgs()
@@ -134,7 +134,7 @@ class RunSetTest(unittest.TestCase):
             chain_ids=chain_ids,
             data=jdata,
             method_args=sampler_args,
-            save_latent_dynamics=True,
+            save_diagnostics=True,
         )
         runset = RunSet(args=cmdstan_args)
         self.assertIn(_TMPDIR, runset.diagnostic_files[0])
@@ -145,7 +145,7 @@ class RunSetTest(unittest.TestCase):
             chain_ids=chain_ids,
             data=jdata,
             method_args=sampler_args,
-            save_latent_dynamics=True,
+            save_diagnostics=True,
             output_dir=os.path.abspath('.'),
         )
         runset = RunSet(args=cmdstan_args)
diff --git a/test/test_sample.py b/test/test_sample.py
index 7af5e13..f60fa2e 100644
--- a/test/test_sample.py
+++ b/test/test_sample.py
@@ -188,34 +188,6 @@ class SampleTest(unittest.TestCase):
         )
         self.assertEqual(bern_fit.draws().shape, (100, 2, len(BERNOULLI_COLS)))
 
-    def test_bernoulli_unit_e(self, stanfile='bernoulli.stan'):
-        stan = os.path.join(DATAFILES_PATH, stanfile)
-        bern_model = CmdStanModel(stan_file=stan)
-
-        jdata = os.path.join(DATAFILES_PATH, 'bernoulli.data.json')
-        bern_fit = bern_model.sample(
-            data=jdata,
-            chains=2,
-            parallel_chains=2,
-            seed=12345,
-            iter_warmup=1000,
-            iter_sampling=100,
-            metric='unit_e',
-        )
-        self.assertEqual(bern_fit.metric_type, 'unit_e')
-        self.assertEqual(bern_fit.step_size.shape, (2,))
-        with LogCapture() as log:
-            logging.getLogger()
-            self.assertEqual(bern_fit.metric, None)
-        log.check_present(
-            (
-                'cmdstanpy',
-                'INFO',
-                'Unit diagnonal metric, inverse mass matrix size unknown.',
-            )
-        )
-        self.assertEqual(bern_fit.draws().shape, (100, 2, len(BERNOULLI_COLS)))
-
     def test_init_types(self):
         stan = os.path.join(DATAFILES_PATH, 'bernoulli.stan')
         bern_model = CmdStanModel(stan_file=stan)
@@ -537,6 +509,7 @@ class SampleTest(unittest.TestCase):
         self.assertEqual(
             datagen_fit.draws().shape, (100, 4, len(datagen_fit.column_names))
         )  # ran 4 chains, set fixed_param=True afterwards
+        self.assertEqual(datagen_fit.num_unconstrained_params, 0)
 
     def test_bernoulli_file_with_space(self):
         self.test_bernoulli_good('bernoulli with space in name.stan')
@@ -790,6 +763,7 @@ class CmdStanMCMCTest(unittest.TestCase):
         csv_path = os.path.join(DATAFILES_PATH, 'fixed_param_sample.csv')
         fixed_param_sample = from_csv(path=csv_path)
         self.assertEqual(fixed_param_sample.draws_pd().shape, (100, 85))
+        self.assertEqual(fixed_param_sample.num_unconstrained_params, 0)
 
     # pylint: disable=no-self-use
     def test_custom_metric(self):
@@ -935,7 +909,7 @@ class CmdStanMCMCTest(unittest.TestCase):
             if os.path.exists(bern_fit.runset.stderr_files[i]):
                 os.remove(bern_fit.runset.stderr_files[i])
 
-        with self.assertRaisesRegex(ValueError, 'Cannot access CSV file'):
+        with self.assertRaisesRegex(ValueError, 'Cannot access csv file'):
             bern_fit.save_csvfiles(dir=DATAFILES_PATH)
 
         if platform.system() != 'Windows':
@@ -1532,6 +1506,7 @@ class CmdStanMCMCTest(unittest.TestCase):
         self.assertEqual(fit.num_draws_warmup, 1000)
         self.assertEqual(fit.num_draws_sampling, 100)
         self.assertEqual(fit.column_names, col_names)
+        self.assertEqual(fit.num_unconstrained_params, 2)
         self.assertEqual(fit.metric_type, 'diag_e')
 
         self.assertEqual(fit.metadata.cmdstan_config['num_samples'], 100)
@@ -1549,7 +1524,7 @@ class CmdStanMCMCTest(unittest.TestCase):
         self.assertEqual(fit.metadata.stan_vars_dims['beta'], tuple([2]))
         self.assertEqual(fit.metadata.stan_vars_cols['beta'], tuple([7, 8]))
 
-    def test_save_latent_dynamics(self):
+    def test_save_diagnostics(self):
         stan = os.path.join(DATAFILES_PATH, 'bernoulli.stan')
         jdata = os.path.join(DATAFILES_PATH, 'bernoulli.data.json')
         bern_model = CmdStanModel(stan_file=stan)
@@ -1559,7 +1534,7 @@ class CmdStanMCMCTest(unittest.TestCase):
             parallel_chains=2,
             seed=12345,
             iter_sampling=200,
-            save_latent_dynamics=True,
+            save_diagnostics=True,
         )
         for i in range(bern_fit.runset.chains):
             diagnostics_file = bern_fit.runset.diagnostic_files[i]
@@ -1584,7 +1559,7 @@ class CmdStanMCMCTest(unittest.TestCase):
             parallel_chains=2,
             seed=12345,
             iter_sampling=200,
-            save_latent_dynamics=True,
+            save_diagnostics=True,
             save_profile=True,
         )