CellML Discussion List

Text archives Help


[cellml-discussion] cmeta:id's and the CCGS


Chronological Thread 
  • From: ak.miller at auckland.ac.nz (Andrew Miller)
  • Subject: [cellml-discussion] cmeta:id's and the CCGS
  • Date: Fri, 29 Dec 2006 13:09:44 +1300

David Nickerson wrote:
> Hi all,
>
> I have been thinking about the best way to map between variables in a
> model and variables in code generated from the model (or more
> precisely the mapping between variables in a model and results from
> numerical simulation of the model using the code generated by the
> CCGS). The typical way to do anything with a particular variable in a
> model is via the variable's cmeta:id (i.e., graph metadata).
>
> Using the current CCGS implementation it is fairly easy to grab the
> original CellML variable object for each variable in the generated
> code and from that you can get the variable's cmeta:id. However, the
> problem is that there can be multiple variables in a model which
> resolve to the same underlying variable in the generated code. Thus,
> when trying to use a particular variable from a model via its cmeta:id
> it may not appear directly in the code, and hence the simulation
> result data.
>
> One way to get all the variables in a model which link to a given
> variable in the generated code is to simply search the model looking
> at connections and source variables, etc. to determine this
> information. An alternate method is to provide this information
> directly via the CCGS - which internally handles all model connections
> in a more efficient manner.
>
> Following up on this I have modified the CCGS to provide a method on
> the CCodeVariable object/interface which provides a character array
> containing a comma separated list of all the cmeta:id's which are
> linked to each code variable (see attached patch for current trunk
> source). For me this works quite well and provides a means to describe
> in the generated code all the variables in a model which are linked to
> a given variable/array index in the generated code.
From an API design perspective, I have a few comments:
Why not just expose the list of variables connected to each variable
from the CCGS? That way, the user can go through the complete list of
all variables efficiently, and check the cmeta:id (or anything else they
want to do) for themselves?

If we are going to expose just the cmeta:id attributes, I don't think a
comma separated list is the right approach. It should ideally be a list
data-structure of some kind, with an iterator interface to iterate
through the cmeta:id values. This is especially relevant given that
RFC3986 (Uniform Resource Identifier (URI): Generic Syntax) allows ,
characters to be present in URIs.

>
> I'm sure the actual implementation is pretty bad, but the general idea
> seems sound to me. What do people think? Perhaps there is already a
> way to do this or something similar, but I couldn't find it. Or maybe
> I'm just going about this in completely the wrong way?
I think we do need to extend the CCGS (or alternatively, make it more
efficient to get the connections information from the CellML API, which
is problematic given that the API is 'live' unlike the CCGS) to support
this.
>
>
> David.
>
> ------------------------------------------------------------------------
>
> Index: CCGS/sources/CCGSGenerator.cpp
> ===================================================================
> --- CCGS/sources/CCGSGenerator.cpp (revision 1014)
> +++ CCGS/sources/CCGSGenerator.cpp (working copy)
> @@ -993,7 +993,7 @@
> (new CDA_CCodeVariable
> ((*i)->GetSourceVariable(), (*i)->GetIndex(),
> ((*i)->GetArray() == VariableInformation::DEPENDENT_AND_RATE),
> - (*i)->GetDegree(), type
> + (*i)->GetDegree(), type, (*i)->GetIDString()
> ));
> }
> }
> Index: CCGS/sources/VariableConnections.cpp
> ===================================================================
> --- CCGS/sources/VariableConnections.cpp (revision 1014)
> +++ CCGS/sources/VariableConnections.cpp (working copy)
> @@ -302,7 +302,17 @@
> aMsg += (*i).second->getSource()->GetName();
> throw CodeGenerationError(aMsg);
> }
> +
> + /* Append the ID */
> + vi->AppendID(var);
>
> + /* ANDRE
> + RETURN_INTO_WSTRING(vn,var->name());
> + printf("variable and source \"%S\"\n",vn.c_str());
> + std::wstring fred = vi->GetIDString();
> + printf(" ID string = \"%S\"\n",fred.c_str());
> + */
> +
> (*i).second->setSource(vi);
>
> // Set the annotation...
> @@ -338,6 +348,17 @@
> RETURN_INTO_OBJREF(vi, VariableInformation,
> new VariableInformation(var, varinfoKey, source));
>
> + /* Append the ID */
> + vi->AppendID(var);
> +
> + /* ANDRE
> + RETURN_INTO_WSTRING(vn,var->name());
> + std::wstring sn = source->GetName();
> + printf("variable \"%S\" has source \"%S\"\n",vn.c_str(),sn.c_str());
> + std::wstring fred = vi->GetIDString();
> + printf(" ID string = \"%S\"\n",fred.c_str());
> + */
> +
> // Set the annotation...
> annot.addAnnotation(vi);
>
> Index: CCGS/sources/CCGSImplementation.hpp
> ===================================================================
> --- CCGS/sources/CCGSImplementation.hpp (revision 1014)
> +++ CCGS/sources/CCGSImplementation.hpp (working copy)
> @@ -144,11 +144,11 @@
> iface::cellml_api::CellMLVariable* aVar, uint32_t aVariableIndex=0,
> bool aHasDifferential=false, uint32_t aDerivative=0,
> iface::cellml_services::VariableEvaluationType aType=
> - iface::cellml_services::COMPUTED
> + iface::cellml_services::COMPUTED, const wchar_t* idString=NULL
>
NULL?

21.3.1 of ISO/IEC 14882-1998 says:
basic_string(const charT* s, const Allocator& a = Allocator());
Requires: s shall not be a null pointer.

Therefore, the default argument value will potentially cause a crash. I
suggest L"" instead.

> )
> : _cda_refcount(1), mVar(aVar), mVariableIndex(aVariableIndex),
> mHasDifferential(aHasDifferential), mDerivative(aDerivative),
> - mType(aType)
> + mType(aType), mIDString(idString)
>
> {
> mVar->add_ref();
> }
> @@ -189,12 +189,28 @@
> return mVar;
> }
>
> + char* ids()
> + throw (std::exception&)
> + {
> + const wchar_t* str = mIDString.c_str();
> + size_t len = wcsrtombs(NULL,&str,0,NULL);
>
Shouldn't you be using UTF16 here, like the rest of the code that deals
with variable names / URIs?
> + if (len > 0)
> + {
> + len++;
> + char* s = (char*)malloc(len);
> + wcsrtombs(s,&str,len,NULL);
> + return(s);
>
> + }
> + return((char*)NULL);
>
NULL is not a valid value for a string in the Physiome CellML Mapping,
because the caller is supposed to be able to pass it to free. You should
return an empty string instead.
> + }
> +
> private:
> iface::cellml_api::CellMLVariable* mVar;
> uint32_t mVariableIndex;
> bool mHasDifferential;
> uint32_t mDerivative;
> iface::cellml_services::VariableEvaluationType mType;
> + std::wstring mIDString;
> };
>
> class CDA_CCodeVariableIterator
> Index: CCGS/sources/Variables.hxx
> ===================================================================
> --- CCGS/sources/Variables.hxx (revision 1014)
> +++ CCGS/sources/Variables.hxx (working copy)
> @@ -12,7 +12,7 @@
> VariableInformation(iface::cellml_api::CellMLVariable* aSourceVariable,
> TemporaryAnnotationKey& aKey)
> : TemporaryAnnotation(aSourceVariable, aKey), mSource(aSourceVariable),
> - mFlags(0), mDegree(1), mSourceInformation(NULL)
> + mFlags(0), mDegree(1), mIDString(), mSourceInformation(NULL)
>
This is unnecessary, as that is the default constructor anyway.
> {
> wchar_t* tmp = aSourceVariable->name();
> mName = tmp;
> @@ -131,12 +131,61 @@
> return mSource;
> }
>
> + /* Andre Hack */
> + void AppendID(iface::cellml_api::CellMLVariable* aVar)
> + {
> + if (mSourceInformation)
> + mSourceInformation->AppendID(aVar);
> + else
> + {
> + /* Does the variable have a cmeta:id? */
> + RETURN_INTO_WSTRING(id,aVar->cmetaId());
> + if (id.length() > 0)
> + {
> + iface::cellml_api::Model* model = aVar->modelElement();
>
I have been trying to use ObjRefs rather than explicit memory management
for all new code. This means that if, for example, base_uri() throws for
some reason, model still won't be leaked.
RETURN_INTO_OBJREF(model, iface::cellml_api::Model, aVar->modelElement())
> + iface::cellml_api::URI* uri = model->base_uri();
>
> + RETURN_INTO_WSTRING(uriS,uri->asText());
> + uriS.append(L"#");
> + uriS.append(id);
> + if (mIDString.length() > 0) mIDString.append(L",");
> + mIDString.append(uriS);
> + uri->release_ref();
> + model->release_ref();
> + }
> + }
> + }
> + const wchar_t* GetIDString()
> + {
> + if (mSourceInformation)
> + return mSourceInformation->GetIDString();
> + else
> + return mIDString.c_str();
> + }
> +
> +#if defined ANDRES_BAD_HACK
> + void SetVariable(iface::cellml_api::CellMLVariable* aVar)
> + {
> + mCellMLElement = aVar;
> + }
> +
> + iface::cellml_api::CellMLVariable* GetVariable()
> + {
> + if (mSourceInformation)
> + return mSourceInformation->GetVariable();
> + else if (mCellMLElement) return
> + dynamic_cast<iface::cellml_api::CellMLVariable*>
> + (mCellMLElement.getPointer());
> + return NULL;
> + }
> +#endif
> +
> const wchar_t* GetName() { return mName.c_str(); }
> private:
> iface::cellml_api::CellMLVariable* mSource;
> double mInitialValue;
> uint32_t mFlags, mDegree, mIndex;
> std::wstring mName;
> + std::wstring mIDString;
> uint32_t mArrayType;
> VariableInformation* mSourceInformation;
> };
> Index: interfaces/CCGS.idl
> ===================================================================
> --- interfaces/CCGS.idl (revision 1014)
> +++ interfaces/CCGS.idl (working copy)
> @@ -80,6 +80,12 @@
> * The CellML variable element of the source (no in interfaces).
> */
> readonly attribute cellml_api::CellMLVariable source;
> +
> + /* Andre's hack */
> + /**
> + * The list of (absolute) IDs referencing this variable.
> + */
> + readonly attribute string ids;
> };
> #pragma terminal-interface
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> cellml-discussion mailing list
> cellml-discussion at cellml.org
> http://www.cellml.org/mailman/listinfo/cellml-discussion
>





Archive powered by MHonArc 2.6.18.

Top of page