NcmModel tutorial
Curve fitting tutorial
Overview
NumCosmo: Defining Models in an Object-Oriented Framework
One of the key objectives of NumCosmo is to provide a comprehensive framework for model fitting. In this tutorial, we will explore the process of defining models within this framework. When modeling a phenomenon, the first step is to identify the key quantities associated with the model and determine how to describe them. In the NumCosmo framework, these aspects are expressed using an Object-Oriented (OO) approach.
The framework encourages the creation of an abstract model that defines only the fundamental quantities. The specific details of these quantities are left to the implementations of the abstract model. Although this separation might initially seem complex, it offers several long-term advantages, including reduced code complexity. Key benefits include:
- Abstract Interface Consistency: Functions and objects that rely on the abstract model can be developed using a standard interface, without concern for specific implementations.
- Clear Model Definition: The approach compels programmers and scientists to clearly distinguish between fundamental quantities of the model and the choices made during implementation.
- Modularity: The framework naturally supports modularity, allowing specific implementations to be modified or replaced without affecting the broader codebase.
- Facilitated Collaboration: Once the abstract model is defined, different groups can independently develop their implementations, simplifying collaborative efforts.
In this tutorial, we will guide you through the process of writing an abstract model in C. While this tutorial focuses on C, writing models in Python is also possible and will be covered in a separate tutorial.
Our abstract model
In this tutorial, we consider the case where we are modeling a phenomenon described by a curve \(f(x)\). In this simple example, it is clear that the only fundamental quantities are the curve \(f(x)\) itself and its domain \([x_l,\; x_u]\). Note that we are not including any specific functional form for \(f(x)\) or any parametrization; these choices are left to the specific implementations of our model.
If you are not familiar with the GObject framework, take a look at this tutorial.
To translate this to an OO framework, we will define an abstract object NcCurve
(subclass of NcmModel
to represent the fundamental quantities. The function \(f(x)\) is represented by the virtual method called nc_curve_f
, and the interval by two properties called xl
and xu
, which represent \(x_l\) and \(x_u\), respectively.
Abstract model header
We include the full header below; however, first, we will highlight the main steps:
Virtual method type
This line determines the prototype of our virtual function. While this step is not strictly necessary – since one could use this prototype directly in the class structure – defining a type improves readability.
typedef gdouble (*NcCurveF) (NcCurve *curve, const gdouble x);
Object class
In the GObject framework, virtual functions are defined as function pointers in the class structure. In this simple example, there is a single virtual function, which we call f
using the type defined above. The class structure is defined as follows:
struct _NcCurveClass
{
/*< private >*/
;
NcmModelClass parent_class;
NcCurveF f};
Implementation enumerator
The NcmModel
framework is designed to support complex models that may involve several virtual methods. Some of these methods may not be required by every implementation. For this reason in introduced the implementation enumerator, this way, the object that use the model may ask if that model implements a specific virtual method. In our example we have a single virtual method, so the enumerator is given by:
typedef enum _NcCurveImpl
{
= 0,
NC_CURVE_IMPL_f } NcCurveImpl;
The enumerator above states that the first bit in the implementation enumerator controls if the child implements this method.
Defining the class id prototype
In order to be able to analyze different models, we need an object to aggregate all necessary models. In NumCosmo this task is performed by the NcmMSet
(model set) object. We use the NCM_MSET_MODEL_DECLARE_ID
macro to declare the id function nc_curve_id
in the NcmMSet
framework.
(nc_curve); NCM_MSET_MODEL_DECLARE_ID
Method prototypes
Finally we declare the two methods necessary to close the implementation (apart from the default ones).
void nc_curve_set_f_impl (NcCurveClass *curve_class, NcCurveF f);
(NcCurve *curve, const gdouble x); gdouble nc_curve_f
The first one just declare the class method that will be used to set the virtual method f
. It is necessary because it has two jobs, it sets the function pointer to the member f
of the class structure and updates the implementation flags to assert that child implements this method.
Abstract model source
We include the full C file below, however, first we are going to highlight the main steps:
Private properties
The first declaration in our code is the definition of the private struct
struct _NcCurvePrivate
{
;
gdouble xl;
gdouble xu};
In principle we could have added these members directly to the NcCurve
struct, however, this would allow users to modify it directly. By hiding it in the compilation unit we avoid this, the only way to modify these values will be through the exported methods. This is important since these methods will perform consistency checks and call all necessary hooks that update the model.
As a rule of thumb, if the access to the struct member is not part of computationally heavy part of the code (here these members are likely to be set just once in the beginning and stay constant throughout all computations), then it just me hidden in the private struct for the reasons described above. Nevertheless, if the member will be accessed constantly during the computations we would attribute it to the object struct and include a inline method to access it, this technique will be discussed in detail in a future tutorial.
Property enumerator
The property enumerator is the part of the GObject framework used to define properties. Here the PROP_0
member is required by the GObject implementation and do not correspond to any actual property. The following members PROP_XL
and PROP_XU
correspond respectively to \(x_l\) and \(x_u\). Finally, PROP_SIZE*
is a convenience member (that we use by convention in NumCosmo) used to count the number of properties, in this case PROP_SIZE == 3
(an enumerator always assign 0 to its first member and +1 to the subsequent, this can be changes by explicitly assigning values).
enum
{
,
PROP_0,
PROP_XL,
PROP_XU,
PROP_SIZE};
Object defining macro
The first step in creating the object is to call the GObject
macro G_DEFINE_ABSTRACT_TYPE. This macro creates an abstract object (that cannot be instantiated) that is a child of NcmModel
.
(NcCurve, nc_curve, NCM_TYPE_MODEL); G_DEFINE_ABSTRACT_TYPE
This macro assumes that two functions will be implemented: - nc_curve_init
: this function should make all necessary initialization to the object that happens before any property is set. This usually consists of assign null or zero value for all struct members. - nc_curve_class_init
: the class method must define all object’s properties and virtual methods.
Object initialization
In this example, the initialization function nc_curve_init
has two tasks, getting the pointer to its private struct and assign the initial values for the properties. Our convention is that if both xl
and xu
are equal to zero then the object is in the initial state.
static void
(NcCurve *curve)
nc_curve_init {
->priv = G_TYPE_INSTANCE_GET_PRIVATE (curve, NC_TYPE_CURVE, NcCurvePrivate);
curve->priv->xl = 0.0;
curve->priv->xu = 0.0;
curve}
Set/Get hooks
In the GObject framework all properties are modified through the set/get hooks. Here we have a two properties, for both we delegate the set/get job to methods implemented below. We could implement it directly inside the enumerators below, however, implementing it in separated functions improve readability.
static void
(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
_nc_curve_set_property {
*curve = NC_CURVE (object);
NcCurve (NC_IS_CURVE (object));
g_return_if_fail
switch (prop_id)
{
case PROP_XL:
(curve, g_value_get_double (value));
nc_curve_set_xl break;
case PROP_XU:
(curve, g_value_get_double (value));
nc_curve_set_xu break;
default:
(object, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID break;
}
}
static void
(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
_nc_curve_get_property {
*curve = NC_CURVE (object);
NcCurve (NC_IS_CURVE (object));
g_return_if_fail
switch (prop_id)
{
case PROP_XL:
(value, nc_curve_get_xl (curve));
g_value_set_double break;
case PROP_XU:
(value, nc_curve_get_xu (curve));
g_value_set_double break;
default:
(object, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID break;
}
}
Defining the id function
The NcmMSet
framework provides the macro NCM_MSET_MODEL_REGISTER_ID that should be used in the object code to create the nc_curve_id function. This function will return the unique ID defined in the NcmMSet
type list.
(nc_curve, NC_TYPE_CURVE); NCM_MSET_MODEL_REGISTER_ID
The class initialization hook
Attributing the Set/Get hooks
In the class initialization hook one must define the object related hooks, as the set/get functions. Since we are using the NcmModel
framework, we need to attribute the set/get hooks to the NcmModelClass
struct. This is necessary since the framework takes care in organizing all model parameters and only the additional properties are handled by the set/get hooks defined here.
* object_class = G_OBJECT_CLASS (klass);
GObjectClass*model_class = NCM_MODEL_CLASS (klass);
NcmModelClass
...
->set_property = &_nc_curve_set_property;
model_class->get_property = &_nc_curve_get_property; model_class
The next step is to initialize the model parameters.
(model_class, "Curve-f", "NcCurve");
ncm_model_class_set_name_nick (model_class, 0, 0, PROP_SIZE); ncm_model_class_add_params
These functions set the model name and nick and tells the framework that it requires 0
scalar parameters and 0
vector parameters and it has additionally PROP_SIZE
properties. It is usually the case that the abstract model has no parameters, this happens because the parameters are usually connected to the specific implementations and not to the abstract definitions.
Registering the ID in NcmMSet
(model_class,
ncm_mset_model_register_id "NcCurve",
"Curve model.",
,
NULL,
FALSE); NCM_MSET_MODEL_MAIN
This functions call takes care in registering the NcCurve
type in the NcmMSet
type list. This is necessary to set/get objects of this type from a NcmMSet
.
Registering the properties
As discussed above, the properties \(x_l\) and \(x_u\) will not be part of the model parameters and will be taken as fixed numbers, in this case, we include them as usual GObject
properties.
(object_class,
g_object_class_install_property ,
PROP_XL("xl",
g_param_spec_double ,
NULL"x lower bound",
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
| G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
G_PARAM_READWRITE (object_class,
g_object_class_install_property ,
PROP_XU("xu",
g_param_spec_double ,
NULL"x upper bound",
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
| G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)); G_PARAM_READWRITE
Checking parameters implementation
The function call below asserts that all required scalar and vector parameters were implemented correctly. In this case, none were required.
(model_class); ncm_model_class_check_params_info
Setting a default implementation for the virtual function
This line sets the default implementation for the virtual function f
.
= &_nc_curve_f; curve_class
Methods
Our implementation of the virtual function f
here is just a placeholder that raises an error if called.
static gdouble
(NcCurve *curve, const gdouble x)
_nc_curve_f {
("nc_curve_f: model `%s' does not implement this function.",
g_error (curve));
G_OBJECT_TYPE_NAME return 0.0;
}
We use the NCM_MODEL_SET_IMPL_FUNC
to generate the code for the implementation function nc_curve_set_f_impl
. This class method, when called by the child implementations will attribute the function to the class struct and enable the implementation flag for this method.
(NC_CURVE, NcCurve, nc_curve, NcCurveF, f) NCM_MODEL_SET_IMPL_FUNC
Example sources
Header
/***************************************************************************
* nc_curve.h
*
* Tue July 11 16:30:36 2017
* Copyright 2017 Sandro Dias Pinto Vitenti
* <vitenti@uel.br>
****************************************************************************/
/*
* nc_curve.h
* Copyright (C) 2017 Sandro Dias Pinto Vitenti <vitenti@uel.br>
*
* numcosmo is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* numcosmo is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NC_CURVE_H_
#define _NC_CURVE_H_
#include <glib.h>
#include <glib-object.h>
#include <numcosmo/build_cfg.h>
/*
* Here we are writing an object external to NumCosmo so we must use
* the full header numcosmo/numcosmo.h. Otherwise we could include
* only the actual header we need, i.e.,
* #include <numcosmo/math/ncm_model.h>
*
*/
#include <numcosmo/numcosmo.h>
G_BEGIN_DECLS
/* These are the basic macros useful for the GObject framework */
#define NC_TYPE_CURVE (nc_curve_get_type ())
#define NC_CURVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NC_TYPE_CURVE, NcCurve))
#define NC_CURVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NC_TYPE_CURVE, NcCurveClass))
#define NC_IS_CURVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NC_TYPE_CURVE))
#define NC_IS_CURVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NC_TYPE_CURVE))
#define NC_CURVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NC_TYPE_CURVE, NcCurveClass))
/*
* This is the class struct, it will contains everything that is
* that is defined across instances.
*
*/
typedef struct _NcCurveClass NcCurveClass;
/*
* This is the instance struct, it will contains everything pertaining
* to a given instance.
*
*/
typedef struct _NcCurve NcCurve;
/*
* This is the instance private struct, it will contains everything
* pertaining that should never be seen outside of the compilation unit.
*
*/
typedef struct _NcCurvePrivate NcCurvePrivate;
/*
* Here we define a type to describe the virtual function which represets
* the actual f(x).
*
*/
typedef gdouble (*NcCurveF) (NcCurve *curve, const gdouble x);
/*
* The class struct contains just one element `f' that must be assigned
* by implementations. The first item is just the parent class structure.
*
*/
struct _NcCurveClass
{
/*< private >*/
;
NcmModelClass parent_class;
NcCurveF f};
/*
* No elements needed apart from our private struct.
* The first item is just the parent object structure.
*
*/
struct _NcCurve
{
/*< private >*/
;
NcmModel parent_instance*priv;
NcCurvePrivate };
/**
* NcCurveImpl:
* @NC_CURVE_F: The curve function $f(x)$.
*
* These flags are used to control which functions each child
* implement. In this case the object is very simple and has
* only one function that may be implement. In more complex cases
* a child could implement only partially the abstract model
* and it would the enumerator to inform which functions are
* actually implement.
*
*/
typedef enum _NcCurveImpl
{
= 0,
NC_CURVE_IMPL_f } NcCurveImpl;
#define NC_CURVE_IMPL_ALL NCM_MODEL_CLASS_IMPL_ALL
(void) G_GNUC_CONST;
GType nc_curve_get_type
/*
* Since this is a abstract model we need to define its ID
* in order to allow it to be found inside of a #NcmMSet
* object.
*
*/
(nc_curve);
NCM_MSET_MODEL_DECLARE_ID
/*
* This function must be used by implementations to set the virtual function f.
*
*/
void nc_curve_set_f_impl (NcCurveClass *curve_class, NcCurveF f);
/*
* The default methods that all objects should implement.
* We also chose to implement a constructor nc_curve_new_from_name()
* to allow creating any child directly.
*
*/
*nc_curve_new_from_name (const gchar *curve_name);
NcCurve *nc_curve_ref (NcCurve *curve);
NcCurve void nc_curve_free (NcCurve *curve);
void nc_curve_clear (NcCurve **curve);
/*
* Property accessors prototypes.
*
*/
void nc_curve_set_xl (NcCurve *curve, const gdouble xl);
void nc_curve_set_xu (NcCurve *curve, const gdouble xu);
(NcCurve *curve);
gdouble nc_curve_get_xl (NcCurve *curve);
gdouble nc_curve_get_xu
/*
* The only quantity calculated by this model is the value
* of $f(x)$, which is represented by the following virtual
* method.
*
*/
(NcCurve *curve, const gdouble x);
gdouble nc_curve_f
G_END_DECLS
#endif /* _NC_CURVE_H_ */
Source
/***************************************************************************
* nc_curve.c
*
* Tue July 11 16:30:26 2017
* Copyright 2017 Sandro Dias Pinto Vitenti
* <vitenti@uel.br>
****************************************************************************/
/*
* nc_curve.c
* Copyright (C) 2017 Sandro Dias Pinto Vitenti <vitenti@uel.br>
*
* numcosmo is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* numcosmo is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:nc_curve
* @title: NcCurve
* @short_description: Abstract class for curves!
*
* NcCurve is the abstract class designed to include the functions
* that any simple curve should implement, see NcCurveImpl.
* Its parent_class is NcmModel.
*
* (This is a gtk-doc comment, which always start with two **)
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include "build_cfg.h"
#include "nc_curve.h"
/*
* All implementations of NcCurve will required the function interval.
* We could have let the interval itself as model parameters in order
* to allow it to be fit too, this approach will be presented in a more
* advanced example.
*
*/
struct _NcCurvePrivate
{
;
gdouble xl;
gdouble xu};
/*
* Properties enumerator, note that we added a last item PROP_SIZE,
* this is useful to obtain the actual number of properties in the
* object without hard coding it. PROP_0 is a special property of
* the GObject system we should always be there.
*
*/
enum
{
,
PROP_0,
PROP_XL,
PROP_XU,
PROP_SIZE};
/*
* Here we define the object GType using the macro G_DEFINE_ABSTRACT_TYPE.
* This macro basically defines the function nc_curve_get_type (void) and
* everything necessary to define an object in the GLib type system. The
* ABSTRACT version of the macro creates a GType that cannot be instantiated
* this means that to use this object we *must* define a child.
*
* The last argument provides the GType of the parent object.
*
*/
(NcCurve, nc_curve, NCM_TYPE_MODEL);
G_DEFINE_ABSTRACT_TYPE
static void
(NcCurve *curve)
nc_curve_init {
/*
* The first step is the creation of the private structure, all allocation and
* de-allocation is automatically performed by the GObject framework.
*/
->priv = G_TYPE_INSTANCE_GET_PRIVATE (curve, NC_TYPE_CURVE, NcCurvePrivate);
curve
/*
* Here we initialize all structure member to null/zero.
*
*/
->priv->xl = 0.0;
curve->priv->xu = 0.0;
curve}
/*
* Here we call all property accessors in order to set property values.
*
*/
static void
(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
_nc_curve_set_property {
*curve = NC_CURVE (object);
NcCurve
(NC_IS_CURVE (object));
g_return_if_fail
switch (prop_id)
{
case PROP_XL:
(curve, g_value_get_double (value));
nc_curve_set_xl break;
case PROP_XU:
(curve, g_value_get_double (value));
nc_curve_set_xu break;
default:
(object, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID break;
}
}
/*
* Here we call all property accessors in order to get property values.
*
*/
static void
(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
_nc_curve_get_property {
*curve = NC_CURVE (object);
NcCurve
(NC_IS_CURVE (object));
g_return_if_fail
switch (prop_id)
{
case PROP_XL:
(value, nc_curve_get_xl (curve));
g_value_set_double break;
case PROP_XU:
(value, nc_curve_get_xu (curve));
g_value_set_double break;
default:
(object, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID break;
}
}
/*
* Here we must de-allocate any memory allocated *inside* gobject framework,
* i.e., we must unref any outside object contained in our object.
*
* Nothing to do!
*
*/
static void
(GObject *object)
_nc_curve_dispose {
/*
* The following comment is always included to remark that at this point the parent
* method must be called, chaining down the function call, i.e., first we finalize
* the properties of the child, if any, then the parent and parent's parent, etc.
*
*/
/* Chain up : end */
(nc_curve_parent_class)->dispose (object);
G_OBJECT_CLASS }
/*
* Here we must de-allocate any memory allocated *outside* gobject framework.
* Nothing to do!
*
*/
static void
(GObject *object)
_nc_curve_finalize {
/*
* The following comment is always included to remark that at this point the parent
* method must be called, chaining down the function call, i.e., first we finalize
* the properties of the child, if any, then the parent and parent's parent, etc.
*
*/
/* Chain up : end */
(nc_curve_parent_class)->finalize (object);
G_OBJECT_CLASS }
/*
* Registry the ID in NumCosmo model system.
*
*/
(nc_curve, NC_TYPE_CURVE);
NCM_MSET_MODEL_REGISTER_ID
/*
* Prototype of the default implementation.
*
*/
static gdouble _nc_curve_f (NcCurve *curve, const gdouble x);
/*
* At _class_init we will define all properties and parameters we should
* also include a default implementation for our virtual function `f'.
*
*/
static void
(NcCurveClass *klass)
nc_curve_class_init {
*object_class = G_OBJECT_CLASS (klass);
GObjectClass *model_class = NCM_MODEL_CLASS (klass);
NcmModelClass
/*
* Tells the type system that we have a private struct
*
*/
(klass, sizeof (NcCurvePrivate));
g_type_class_add_private
/*
* The NcmModel class takes cares of the parameters, thus,
* the set/get functions above must be set in NcmModelClass
* structure.
*
*/
->set_property = &_nc_curve_set_property;
model_class->get_property = &_nc_curve_get_property;
model_class
/*
* The other functions are the usual GObject hooks and
* must be assigned to GObjectClass.
*
*/
->dispose = &_nc_curve_dispose;
object_class->finalize = &_nc_curve_finalize;
object_class
/*
* First we set the model nick `Curve-f' and its name
*
*/
(model_class, "Curve-f", "NcCurve");
ncm_model_class_set_name_nick
/*
* Now we inform that we have 0 scalar parameters and 0 vector parameters.
* Note that here we should include parameters that *all* implementations
* would share, here we have none. Finallt, with the last argument we assert
* that we have PROP_SIZE == 2 additional properties.
*
*/
(model_class, 0, 0, PROP_SIZE);
ncm_model_class_add_params
/*
* Next step is to register the object in NumCosmo's model set object class.
* We don't include a long description (first NULL below). The last arguments
* FALSE and NCM_MSET_MODEL_MAIN determines that this object in non-stackable
* and it is a MAIN model, both concepts will be discussed in an advanced example.
*
*/
(model_class,
ncm_mset_model_register_id "NcCurve",
"Curve model.",
,
NULL,
FALSE);
NCM_MSET_MODEL_MAIN
/*
* The property PROP_XL is allowed in range [-G_MAXDOUBLE, G_MAXDOUBLE]
* and its default value is 0.0. This property can be set only during
* the object construction.
*
*/
(object_class,
g_object_class_install_property ,
PROP_XL("xl",
g_param_spec_double ,
NULL"x lower bound",
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
| G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
G_PARAM_READWRITE
/*
* The property PROP_XU is allowed in range [-G_MAXDOUBLE, G_MAXDOUBLE]
* and its default value is 1.0. This property can be set only during
* the object construction.
*
*/
(object_class,
g_object_class_install_property ,
PROP_XU("xu",
g_param_spec_double ,
NULL"x upper bound",
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
| G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
G_PARAM_READWRITE
/*
* Check for errors in parameters initialization.
*
*/
(model_class);
ncm_model_class_check_params_info
= &_nc_curve_f;
curve_class }
/*
* Default implementation. It raises an error if the method is called
* and the child didn't implement it.
*
*/
static gdouble
(NcCurve *curve, const gdouble x)
_nc_curve_f {
("nc_curve_f: model `%s' does not implement this function.",
g_error (curve));
G_OBJECT_TYPE_NAME
return 0.0;
}
/*
* This creates a function to be used by the children to
* implement this method.
*
*/
/**
* nc_curve_set_f_impl: (skip)
* @curve_class: a #NcCurveClass
* @f: function $f(x)$
*
* Sets the implementation of the curve $f(x)$.
*
*/
(NC_CURVE, NcCurve, nc_curve, NcCurveF, f)
NCM_MODEL_SET_IMPL_FUNC
/*
* This defines a generic constructor for the subclasses
*
*/
/**
* nc_curve_new_from_name:
* @curve_name: #NcCurve child type name
*
* Creates a new #NcCurve of the type described by @curve_name.
*
* Returns: (transfer full): a new #NcCurve
*/
*
NcCurve (const gchar *curve_name)
nc_curve_new_from_name {
/*
* We use the serialization object to transform a string into an instance.
* This also allows us to chose the parameters through the string.
*
*/
*obj = ncm_serialize_global_from_string (curve_name);
GObject
/*
* This gets the GType of this new instance.
*
*/
= G_OBJECT_TYPE (obj);
GType curve_type
/*
* Check if the string represent an actual child of #NcCurve.
*
*/
if (!g_type_is_a (curve_type, NC_TYPE_CLUSTER_MASS))
("nc_curve_new_from_name: NcCurve `%s' do not descend from `%s'.",
g_error , g_type_name (NC_TYPE_CURVE));
curve_name
/*
* Returns the correct cast.
*
*/
return NC_CURVE (obj);
}
/*
* The reference increasing function
*
*/
/**
* nc_curve_ref:
* @curve: a #NcCurve
*
* Increase reference count by one.
*
* Returns: (transfer full): @curve.
*/
*
NcCurve (NcCurve *curve)
nc_curve_ref {
return g_object_ref (curve);
}
/*
* The reference decreasing function
*
*/
/**
* nc_curve_free:
* @curve: a #NcCurve
*
* Decrease reference count by one.
*
*/
void
(NcCurve *curve)
nc_curve_free {
(curve);
g_object_unref }
/*
* This function decreases the reference count
* by one only if *curve != NULL, and in that case
* it sets *curve to NULL after decreasing the
* reference count. It is useful to use these
* functions in the dispose hooks.
*
*
*/
/**
* nc_curve_clear:
* @curve: a #NcCurve
*
* Decrease reference count by one if *@curve != NULL
* and sets @curve to NULL.
*
*/
void
(NcCurve **curve)
nc_curve_clear {
(curve);
g_clear_object }
/*
* Below we implement the accessor functions.
*
*/
/**
* nc_curve_set_xl:
* @curve: a #NcCurve
* @xl: new $x$ lower bound
*
* Sets $x$ lower bound to @xl.
*
*/
void
(NcCurve *curve, const gdouble xl)
nc_curve_set_xl {
/*
* Checking if the object is still in the unintitalized state,
* if that's the case just assign the value to the private
* struct.
*
*/
if ((curve->priv->xl == 0.0) && (curve->priv->xl == curve->priv->xu))
{
->priv->xl = xl;
curve}
else
{
/*
* Otherwise assert that xl will be less than xu.
*
*/
(xl, <, curve->priv->xu);
g_assert_cmpfloat ->priv->xl = xl;
curve}
}
/**
* nc_curve_set_xu:
* @curve: a #NcCurve
* @xu: new $x$ upper bound
*
* Sets $x$ upper bound to @xu.
*
*/
void
(NcCurve *curve, const gdouble xu)
nc_curve_set_xu {
/*
* Checking if the object is still in the unintitalized state,
* if that's the case just assign the value to the private
* struct.
*
*/
if ((curve->priv->xl == 0.0) && (curve->priv->xl == curve->priv->xu))
{
->priv->xu = xu;
curve}
else
{
/*
* Otherwise assert that xl will be less than xu.
*
*/
(curve->priv->xl, <, xu);
g_assert_cmpfloat ->priv->xu = xu;
curve}
}
/**
* nc_curve_get_xl:
* @curve: a #NcCurve
*
* Sets $x$ lower bound.
*
* Returns: $x_l$.
*/
gdouble(NcCurve *curve)
nc_curve_get_xl {
return curve->priv->xl;
}
/**
* nc_curve_get_xu:
* @curve: a #NcCurve
*
* Sets $x$ lower bound.
*
* Returns: $x_l$.
*/
gdouble(NcCurve *curve)
nc_curve_get_xu {
return curve->priv->xu;
}
/*
* Finally, we implement the generic caller for the
* virtual function `f'.
*
*/
/**
* nc_curve_f: (virtual f)
* @curve: a #NcCurve
* @x: $x$
*
* Computes $f(x)$.
*
* Returns: the value of $f(x)$.
*/
gdouble(NcCurve *curve, const gdouble x)
nc_curve_f {
/*
* This function call by pointer guarantees that
* the correct virtual function will be called.
*
*/
return NC_CURVE_GET_CLASS (curve)->f (curve, x);
}